Rollup merge of #124896 - RalfJung:miri-intrinsic-fallback, r=oli-obk

miri: rename intrinsic_fallback_checks_ub to intrinsic_fallback_is_spec

Checking UB is not the only concern, we also have to make sure we are not losing out on non-determinism.

r? ``@oli-obk`` (not urgent, take your time)
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000..ca70408
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,10 @@
+<!--
+If this PR is related to an unstable feature or an otherwise tracked effort,
+please link to the relevant tracking issue here. If you don't know of a related
+tracking issue or there are none, feel free to ignore this.
+
+This PR will get automatically assigned to a reviewer. In case you would like
+a specific user to review your work, you can assign it to them by using
+
+    r​? <reviewer name>
+-->
\ No newline at end of file
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index a2769a2..0551d44 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -52,6 +52,8 @@
       - name: Checkout the source code
         uses: actions/checkout@v4
       - name: Calculate the CI job matrix
+        env:
+          COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
         run: python3 src/ci/github-actions/calculate-job-matrix.py >> $GITHUB_OUTPUT
         id: jobs
   job:
@@ -75,14 +77,6 @@
       matrix:
         # Check the `calculate_matrix` job to see how is the matrix defined.
         include: ${{ fromJSON(needs.calculate_matrix.outputs.jobs) }}
-    # GitHub Actions fails the workflow if an empty list of jobs is provided to
-    # the workflow, so we need to skip this job if nothing was produced by
-    # the Python script.
-    #
-    # Unfortunately checking whether a list is empty is not possible in a nice
-    # way due to GitHub Actions expressions limits.
-    # This hack is taken from https://github.com/ferrocene/ferrocene/blob/d43edc6b7697cf1719ec1c17c54904ab94825763/.github/workflows/release.yml#L75-L82
-    if: fromJSON(needs.calculate_matrix.outputs.jobs)[0] != null
     steps:
       - if: contains(matrix.os, 'windows')
         uses: msys2/setup-msys2@v2.22.0
@@ -196,7 +190,6 @@
         env:
           AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }}
           AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}
-          TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
 
       - name: create github artifacts
         run: src/ci/scripts/create-doc-artifacts.sh
@@ -247,3 +240,5 @@
         if: needs.calculate_matrix.outputs.run_type == 'auto'
         env:
           TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
+          TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
+          TOOLSTATE_PUBLISH: 1
diff --git a/.github/workflows/dependencies.yml b/.github/workflows/dependencies.yml
index f4e409e..03584ae 100644
--- a/.github/workflows/dependencies.yml
+++ b/.github/workflows/dependencies.yml
@@ -56,7 +56,7 @@
       - name: install the bootstrap toolchain
         run: |
           # Extract the stage0 version
-          TOOLCHAIN=$(jq -r '.compiler | {version,date} | join("-")' -- src/stage0.json)
+          TOOLCHAIN=$(awk -F= '{a[$1]=$2} END {print(a["compiler_version"] "-" a["compiler_date"])}' src/stage0)
           # Install and set as default
           rustup toolchain install --no-self-update --profile minimal $TOOLCHAIN
           rustup default $TOOLCHAIN
diff --git a/.gitmodules b/.gitmodules
index 802d61e..9ad207a 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -33,7 +33,7 @@
 [submodule "src/llvm-project"]
 	path = src/llvm-project
 	url = https://github.com/rust-lang/llvm-project.git
-	branch = rustc/18.0-2024-02-13
+	branch = rustc/18.1-2024-05-19
 	shallow = true
 [submodule "src/doc/embedded-book"]
 	path = src/doc/embedded-book
@@ -43,3 +43,7 @@
 	path = library/backtrace
 	url = https://github.com/rust-lang/backtrace-rs.git
 	shallow = true
+[submodule "src/tools/rustc-perf"]
+	path = src/tools/rustc-perf
+	url = https://github.com/rust-lang/rustc-perf.git
+	shallow = true
diff --git a/Cargo.lock b/Cargo.lock
index 84f7d21..3a4f028 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -68,17 +68,17 @@
 
 [[package]]
 name = "allocator-api2"
-version = "0.2.16"
+version = "0.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
+checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
 
 [[package]]
 name = "ammonia"
-version = "3.3.0"
+version = "4.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64e6d1c7838db705c9b756557ee27c384ce695a1c51a6fe528784cb1c6840170"
+checksum = "1ab99eae5ee58501ab236beb6f20f6ca39be615267b014899c89b2f0bc18a459"
 dependencies = [
- "html5ever",
+ "html5ever 0.27.0",
  "maplit",
  "once_cell",
  "tendril",
@@ -141,56 +141,57 @@
 
 [[package]]
 name = "anstream"
-version = "0.6.13"
+version = "0.6.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
+checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
 dependencies = [
  "anstyle",
  "anstyle-parse",
  "anstyle-query",
  "anstyle-wincon",
  "colorchoice",
+ "is_terminal_polyfill",
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle"
-version = "1.0.6"
+version = "1.0.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
+checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
 
 [[package]]
 name = "anstyle-lossy"
-version = "1.1.0"
+version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9a0444767dbd4aea9355cb47a370eb184dbfe918875e127eff52cb9d1638181"
+checksum = "6fcff6599f06e21b0165c85052ccd6e67dc388ddd1c516a9dc5f55dc8cacf004"
 dependencies = [
  "anstyle",
 ]
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.3"
+version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
+checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
 dependencies = [
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle-query"
-version = "1.0.2"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
+checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5"
 dependencies = [
  "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "anstyle-svg"
-version = "0.1.3"
+version = "0.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8b6ddad447b448d6d5db36b31cbd3ff27c7af071619501998eeceab01968287a"
+checksum = "bbbf0bf947d663010f0b4132f28ca08da9151f3b9035fa7578a38de521c1d1aa"
 dependencies = [
  "anstream",
  "anstyle",
@@ -201,9 +202,9 @@
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.2"
+version = "3.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
+checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
 dependencies = [
  "anstyle",
  "windows-sys 0.52.0",
@@ -211,9 +212,9 @@
 
 [[package]]
 name = "anyhow"
-version = "1.0.81"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
 dependencies = [
  "backtrace",
 ]
@@ -256,7 +257,7 @@
  "proc-macro2",
  "quote",
  "serde",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -276,9 +277,9 @@
 
 [[package]]
 name = "autocfg"
-version = "1.2.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
 
 [[package]]
 name = "backtrace"
@@ -380,27 +381,24 @@
 version = "0.1.0"
 dependencies = [
  "anyhow",
+ "build_helper",
  "curl",
  "indexmap",
  "serde",
- "serde_json",
  "toml 0.5.11",
 ]
 
 [[package]]
 name = "bumpalo"
-version = "3.15.4"
+version = "3.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
 
 [[package]]
 name = "bytecount"
-version = "0.6.7"
+version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205"
-dependencies = [
- "packed_simd",
-]
+checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce"
 
 [[package]]
 name = "byteorder"
@@ -416,9 +414,9 @@
 
 [[package]]
 name = "camino"
-version = "1.1.6"
+version = "1.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c"
+checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239"
 dependencies = [
  "serde",
 ]
@@ -479,9 +477,9 @@
 
 [[package]]
 name = "cc"
-version = "1.0.92"
+version = "1.0.97"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2678b2e3449475e95b0aa6f9b506a28e61b3dc8996592b983695e8ebb58a8b41"
+checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
 
 [[package]]
 name = "cfg-if"
@@ -509,7 +507,7 @@
  "iana-time-zone",
  "num-traits",
  "serde",
- "windows-targets 0.52.4",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
@@ -573,15 +571,15 @@
  "anstream",
  "anstyle",
  "clap_lex",
- "strsim 0.11.1",
+ "strsim",
  "terminal_size",
 ]
 
 [[package]]
 name = "clap_complete"
-version = "4.5.1"
+version = "4.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "885e4d7d5af40bfb99ae6f9433e292feac98d452dcb3ec3d25dfe7552b77da8c"
+checksum = "dd79504325bf38b10165b02e89b4347300f855f273c4cb30c4a3209e6583275e"
 dependencies = [
  "clap",
 ]
@@ -595,7 +593,7 @@
  "heck 0.5.0",
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -622,7 +620,7 @@
  "regex",
  "rustc_tools_util",
  "serde",
- "syn 2.0.58",
+ "syn 2.0.64",
  "tempfile",
  "termize",
  "tokio",
@@ -649,7 +647,7 @@
  "clap",
  "indoc",
  "itertools 0.12.1",
- "opener",
+ "opener 0.6.1",
  "shell-escape",
  "walkdir",
 ]
@@ -716,23 +714,23 @@
 
 [[package]]
 name = "color-print"
-version = "0.3.5"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a858372ff14bab9b1b30ea504f2a4bc534582aee3e42ba2d41d2a7baba63d5d"
+checksum = "1ee543c60ff3888934877a5671f45494dd27ed4ba25c6670b9a7576b7ed7a8c0"
 dependencies = [
  "color-print-proc-macro",
 ]
 
 [[package]]
 name = "color-print-proc-macro"
-version = "0.3.5"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57e37866456a721d0a404439a1adae37a31be4e0055590d053dfe6981e05003f"
+checksum = "77ff1a80c5f3cb1ca7c06ffdd71b6a6dd6d8f896c42141fbd43f50ed28dcdb93"
 dependencies = [
  "nom",
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -749,9 +747,9 @@
 
 [[package]]
 name = "colorchoice"
-version = "1.0.0"
+version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
+checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
 
 [[package]]
 name = "colored"
@@ -828,16 +826,6 @@
 ]
 
 [[package]]
-name = "core-foundation"
-version = "0.9.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
 name = "core-foundation-sys"
 version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -959,9 +947,9 @@
 
 [[package]]
 name = "darling"
-version = "0.20.8"
+version = "0.20.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391"
+checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1"
 dependencies = [
  "darling_core",
  "darling_macro",
@@ -969,27 +957,27 @@
 
 [[package]]
 name = "darling_core"
-version = "0.20.8"
+version = "0.20.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f"
+checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120"
 dependencies = [
  "fnv",
  "ident_case",
  "proc-macro2",
  "quote",
- "strsim 0.10.0",
- "syn 2.0.58",
+ "strsim",
+ "syn 2.0.64",
 ]
 
 [[package]]
 name = "darling_macro"
-version = "0.20.8"
+version = "0.20.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
+checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178"
 dependencies = [
  "darling_core",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -999,12 +987,23 @@
 checksum = "a0afaad2b26fa326569eb264b1363e8ae3357618c43982b3f285f0774ce76b69"
 
 [[package]]
+name = "dbus"
+version = "0.9.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b"
+dependencies = [
+ "libc",
+ "libdbus-sys",
+ "winapi",
+]
+
+[[package]]
 name = "declare_clippy_lint"
 version = "0.1.80"
 dependencies = [
  "itertools 0.12.1",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -1045,7 +1044,7 @@
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -1055,7 +1054,7 @@
 checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b"
 dependencies = [
  "derive_builder_core",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -1078,7 +1077,7 @@
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -1167,14 +1166,14 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
 name = "dissimilar"
-version = "1.0.7"
+version = "1.0.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632"
+checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d"
 
 [[package]]
 name = "dlmalloc"
@@ -1191,9 +1190,9 @@
 
 [[package]]
 name = "either"
-version = "1.10.0"
+version = "1.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
+checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
 
 [[package]]
 name = "elasticlunr-rs"
@@ -1218,9 +1217,9 @@
 
 [[package]]
 name = "ena"
-version = "0.14.2"
+version = "0.14.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
+checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5"
 dependencies = [
  "log",
 ]
@@ -1232,15 +1231,6 @@
 checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
 
 [[package]]
-name = "encoding_rs"
-version = "0.8.33"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
 name = "env_filter"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1271,9 +1261,9 @@
 
 [[package]]
 name = "errno"
-version = "0.3.8"
+version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
+checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
 dependencies = [
  "libc",
  "windows-sys 0.52.0",
@@ -1314,9 +1304,9 @@
 
 [[package]]
 name = "fastrand"
-version = "2.0.2"
+version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "658bd65b1cf4c852a3cc96f18a8ce7b5640f6b703f905c7d74532294c2a63984"
+checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a"
 
 [[package]]
 name = "field-offset"
@@ -1336,15 +1326,15 @@
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.4.1",
  "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "flate2"
-version = "1.0.28"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
+checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
 dependencies = [
  "crc32fast",
  "miniz_oxide",
@@ -1352,9 +1342,9 @@
 
 [[package]]
 name = "fluent-bundle"
-version = "0.15.2"
+version = "0.15.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e242c601dec9711505f6d5bbff5bedd4b61b2469f2e8bb8e57ee7c9747a87ffd"
+checksum = "7fe0a21ee80050c678013f82edf4b705fe2f26f1f9877593d13198612503f493"
 dependencies = [
  "fluent-langneg",
  "fluent-syntax",
@@ -1377,9 +1367,9 @@
 
 [[package]]
 name = "fluent-syntax"
-version = "0.11.0"
+version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0abed97648395c902868fee9026de96483933faa54ea3b40d652f7dfe61ca78"
+checksum = "2a530c4694a6a8d528794ee9bbd8ba0122e779629ac908d15ad5a7ae7763a33d"
 dependencies = [
  "thiserror",
 ]
@@ -1391,21 +1381,6 @@
 checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
 [[package]]
-name = "foreign-types"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
-dependencies = [
- "foreign-types-shared",
-]
-
-[[package]]
-name = "foreign-types-shared"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
-
-[[package]]
 name = "form_urlencoded"
 version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1505,7 +1480,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -1577,9 +1552,9 @@
 
 [[package]]
 name = "getrandom"
-version = "0.2.13"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a06fddc2749e0528d2813f95e050e87e52c8cbbae56223b9babf73b3e53b0cc6"
+checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
 dependencies = [
  "cfg-if",
  "libc",
@@ -1629,25 +1604,6 @@
 ]
 
 [[package]]
-name = "h2"
-version = "0.3.26"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8"
-dependencies = [
- "bytes",
- "fnv",
- "futures-core",
- "futures-sink",
- "futures-util",
- "http",
- "indexmap",
- "slab",
- "tokio",
- "tokio-util",
- "tracing",
-]
-
-[[package]]
 name = "handlebars"
 version = "5.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1663,9 +1619,9 @@
 
 [[package]]
 name = "hashbrown"
-version = "0.14.3"
+version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
 dependencies = [
  "ahash",
  "allocator-api2",
@@ -1737,47 +1693,27 @@
 dependencies = [
  "log",
  "mac",
- "markup5ever",
+ "markup5ever 0.11.0",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
 ]
 
 [[package]]
-name = "http"
-version = "0.2.12"
+name = "html5ever"
+version = "0.27.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
+checksum = "c13771afe0e6e846f1e67d038d4cb29998a6779f93c809212e4e9c32efd244d4"
 dependencies = [
- "bytes",
- "fnv",
- "itoa",
+ "log",
+ "mac",
+ "markup5ever 0.12.1",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.64",
 ]
 
 [[package]]
-name = "http-body"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
-dependencies = [
- "bytes",
- "http",
- "pin-project-lite",
-]
-
-[[package]]
-name = "httparse"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
-
-[[package]]
-name = "httpdate"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
-
-[[package]]
 name = "humansize"
 version = "2.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1793,43 +1729,6 @@
 checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
 [[package]]
-name = "hyper"
-version = "0.14.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
-dependencies = [
- "bytes",
- "futures-channel",
- "futures-core",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "httparse",
- "httpdate",
- "itoa",
- "pin-project-lite",
- "socket2",
- "tokio",
- "tower-service",
- "tracing",
- "want",
-]
-
-[[package]]
-name = "hyper-tls"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
-dependencies = [
- "bytes",
- "hyper",
- "native-tls",
- "tokio",
- "tokio-native-tls",
-]
-
-[[package]]
 name = "iana-time-zone"
 version = "0.1.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1943,7 +1842,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -2046,18 +1945,18 @@
 
 [[package]]
 name = "instant"
-version = "0.1.12"
+version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
+checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
 dependencies = [
  "cfg-if",
 ]
 
 [[package]]
 name = "intl-memoizer"
-version = "0.5.1"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c310433e4a310918d6ed9243542a6b83ec1183df95dff8f23f87bb88a264a66f"
+checksum = "fe22e020fce238ae18a6d5d8c502ee76a52a6e880d99477657e6acc30ec57bda"
 dependencies = [
  "type-map",
  "unic-langid",
@@ -2073,10 +1972,10 @@
 ]
 
 [[package]]
-name = "ipnet"
-version = "2.9.0"
+name = "is_terminal_polyfill"
+version = "1.70.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
+checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
 
 [[package]]
 name = "itertools"
@@ -2114,9 +2013,9 @@
 
 [[package]]
 name = "jobserver"
-version = "0.1.28"
+version = "0.1.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab46a6e9526ddef3ae7f787c06f0f2600639ba80ea3eade3d8e670a2230f51d6"
+checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
 dependencies = [
  "libc",
 ]
@@ -2186,14 +2085,24 @@
 
 [[package]]
 name = "libc"
-version = "0.2.153"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 dependencies = [
  "rustc-std-workspace-core",
 ]
 
 [[package]]
+name = "libdbus-sys"
+version = "0.2.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72"
+dependencies = [
+ "cc",
+ "pkg-config",
+]
+
+[[package]]
 name = "libffi"
 version = "3.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2219,7 +2128,7 @@
 checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
 dependencies = [
  "cfg-if",
- "windows-targets 0.48.5",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
@@ -2254,7 +2163,7 @@
 name = "linkchecker"
 version = "0.1.0"
 dependencies = [
- "html5ever",
+ "html5ever 0.26.0",
  "regex",
 ]
 
@@ -2269,9 +2178,9 @@
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.13"
+version = "0.4.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
+checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
 
 [[package]]
 name = "litemap"
@@ -2296,9 +2205,9 @@
 
 [[package]]
 name = "lock_api"
-version = "0.4.11"
+version = "0.4.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -2348,6 +2257,20 @@
 ]
 
 [[package]]
+name = "markup5ever"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16ce3abbeba692c8b8441d036ef91aea6df8da2c6b6e21c7e14d3c18e526be45"
+dependencies = [
+ "log",
+ "phf 0.11.2",
+ "phf_codegen 0.11.2",
+ "string_cache",
+ "string_cache_codegen",
+ "tendril",
+]
+
+[[package]]
 name = "matchers"
 version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2368,9 +2291,9 @@
 
 [[package]]
 name = "mdbook"
-version = "0.4.37"
+version = "0.4.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c33564061c3c640bed5ace7d6a2a1b65f2c64257d1ac930c15e94ed0fb561d3"
+checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -2383,8 +2306,8 @@
  "log",
  "memchr",
  "once_cell",
- "opener",
- "pulldown-cmark 0.10.2",
+ "opener 0.7.1",
+ "pulldown-cmark 0.10.3",
  "regex",
  "serde",
  "serde_json",
@@ -2466,9 +2389,9 @@
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.2"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
+checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae"
 dependencies = [
  "adler",
  "compiler_builtins",
@@ -2477,17 +2400,6 @@
 ]
 
 [[package]]
-name = "mio"
-version = "0.8.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c"
-dependencies = [
- "libc",
- "wasi",
- "windows-sys 0.48.0",
-]
-
-[[package]]
 name = "miow"
 version = "0.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2525,24 +2437,6 @@
 version = "0.1.0"
 
 [[package]]
-name = "native-tls"
-version = "0.2.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
-dependencies = [
- "lazy_static",
- "libc",
- "log",
- "openssl",
- "openssl-probe",
- "openssl-sys",
- "schannel",
- "security-framework",
- "security-framework-sys",
- "tempfile",
-]
-
-[[package]]
 name = "new_debug_unreachable"
 version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2615,12 +2509,11 @@
 
 [[package]]
 name = "num-traits"
-version = "0.2.18"
+version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
 dependencies = [
  "autocfg",
- "libm",
 ]
 
 [[package]]
@@ -2695,29 +2588,15 @@
 ]
 
 [[package]]
-name = "openssl"
-version = "0.10.64"
+name = "opener"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
+checksum = "f8df34be653210fbe9ffaff41d3b92721c56ce82dfee58ee684f9afb5e3a90c0"
 dependencies = [
- "bitflags 2.5.0",
- "cfg-if",
- "foreign-types",
- "libc",
- "once_cell",
- "openssl-macros",
- "openssl-sys",
-]
-
-[[package]]
-name = "openssl-macros"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.58",
+ "bstr",
+ "dbus",
+ "normpath",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -2753,15 +2632,13 @@
  "humansize",
  "humantime",
  "log",
- "reqwest",
  "serde",
  "serde_json",
  "sysinfo",
  "tabled",
  "tar",
  "tempfile",
- "xz",
- "zip",
+ "xz2",
 ]
 
 [[package]]
@@ -2783,16 +2660,6 @@
 checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f"
 
 [[package]]
-name = "packed_simd"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f9f08af0c877571712e2e3e686ad79efad9657dbf0f7c3c8ba943ff6c38932d"
-dependencies = [
- "cfg-if",
- "num-traits",
-]
-
-[[package]]
 name = "pad"
 version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2837,9 +2704,9 @@
 
 [[package]]
 name = "parking_lot"
-version = "0.12.1"
+version = "0.12.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
 dependencies = [
  "lock_api",
  "parking_lot_core",
@@ -2847,15 +2714,15 @@
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.9"
+version = "0.9.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.5.1",
  "smallvec",
- "windows-targets 0.48.5",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
@@ -2890,9 +2757,9 @@
 
 [[package]]
 name = "pest"
-version = "2.7.9"
+version = "2.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95"
+checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8"
 dependencies = [
  "memchr",
  "thiserror",
@@ -2901,9 +2768,9 @@
 
 [[package]]
 name = "pest_derive"
-version = "2.7.9"
+version = "2.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c"
+checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459"
 dependencies = [
  "pest",
  "pest_generator",
@@ -2911,22 +2778,22 @@
 
 [[package]]
 name = "pest_generator"
-version = "2.7.9"
+version = "2.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd"
+checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687"
 dependencies = [
  "pest",
  "pest_meta",
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
 name = "pest_meta"
-version = "2.7.9"
+version = "2.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca"
+checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd"
 dependencies = [
  "once_cell",
  "pest",
@@ -3080,9 +2947,9 @@
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.79"
+version = "1.0.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
+checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
 dependencies = [
  "unicode-ident",
 ]
@@ -3126,9 +2993,9 @@
 
 [[package]]
 name = "pulldown-cmark"
-version = "0.10.2"
+version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f0530d13d87d1f549b66a3e8d0c688952abe5994e204ed62615baaf25dc029c"
+checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993"
 dependencies = [
  "bitflags 2.5.0",
  "memchr",
@@ -3138,9 +3005,9 @@
 
 [[package]]
 name = "pulldown-cmark-escape"
-version = "0.10.0"
+version = "0.10.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5d8f9aa0e3cbcfaf8bf00300004ee3b72f74770f9cbac93f6928771f613276b"
+checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3"
 
 [[package]]
 name = "punycode"
@@ -3156,9 +3023,9 @@
 
 [[package]]
 name = "quote"
-version = "1.0.35"
+version = "1.0.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
 dependencies = [
  "proc-macro2",
 ]
@@ -3262,6 +3129,15 @@
 ]
 
 [[package]]
+name = "redox_syscall"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
+dependencies = [
+ "bitflags 2.5.0",
+]
+
+[[package]]
 name = "redox_users"
 version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3348,46 +3224,6 @@
 ]
 
 [[package]]
-name = "reqwest"
-version = "0.11.27"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62"
-dependencies = [
- "base64",
- "bytes",
- "encoding_rs",
- "futures-core",
- "futures-util",
- "h2",
- "http",
- "http-body",
- "hyper",
- "hyper-tls",
- "ipnet",
- "js-sys",
- "log",
- "mime",
- "native-tls",
- "once_cell",
- "percent-encoding",
- "pin-project-lite",
- "rustls-pemfile",
- "serde",
- "serde_json",
- "serde_urlencoded",
- "sync_wrapper",
- "system-configuration",
- "tokio",
- "tokio-native-tls",
- "tower-service",
- "url",
- "wasm-bindgen",
- "wasm-bindgen-futures",
- "web-sys",
- "winreg",
-]
-
-[[package]]
 name = "rls"
 version = "2.0.0"
 dependencies = [
@@ -3424,9 +3260,9 @@
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.4.7"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab1dbbd1bdf65fdac44c885f6cca147ba179108ce284b60a08ccc04b1f1dbac0"
+checksum = "fa3ca63cc537c1cb69e4c2c0afc5fda2ccd36ac84c97d5a4ae05e69b1c834afb"
 dependencies = [
  "anyhow",
  "rustc_version",
@@ -3436,9 +3272,9 @@
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.23"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
@@ -3746,8 +3582,10 @@
 version = "0.0.0"
 dependencies = [
  "ar_archive_writer",
+ "arrayvec",
  "bitflags 2.5.0",
  "cc",
+ "either",
  "itertools 0.12.1",
  "jobserver",
  "libc",
@@ -3997,7 +3835,7 @@
  "fluent-syntax",
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
  "unic-langid",
 ]
 
@@ -4131,7 +3969,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
  "synstructure",
 ]
 
@@ -4278,7 +4116,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
  "synstructure",
 ]
 
@@ -4339,6 +4177,7 @@
  "rustc_hir_pretty",
  "rustc_index",
  "rustc_macros",
+ "rustc_next_trait_solver",
  "rustc_query_system",
  "rustc_serialize",
  "rustc_session",
@@ -4365,6 +4204,7 @@
  "rustc_hir",
  "rustc_index",
  "rustc_infer",
+ "rustc_lint",
  "rustc_macros",
  "rustc_middle",
  "rustc_pattern_analysis",
@@ -4446,7 +4286,13 @@
 name = "rustc_next_trait_solver"
 version = "0.0.0"
 dependencies = [
+ "derivative",
+ "rustc_ast_ir",
+ "rustc_data_structures",
+ "rustc_macros",
+ "rustc_serialize",
  "rustc_type_ir",
+ "rustc_type_ir_macros",
 ]
 
 [[package]]
@@ -4747,6 +4593,7 @@
 version = "0.0.0"
 dependencies = [
  "bitflags 2.5.0",
+ "derivative",
  "itertools 0.12.1",
  "rustc_ast",
  "rustc_ast_ir",
@@ -4762,10 +4609,13 @@
  "rustc_next_trait_solver",
  "rustc_parse_format",
  "rustc_query_system",
+ "rustc_serialize",
  "rustc_session",
  "rustc_span",
  "rustc_target",
  "rustc_transmute",
+ "rustc_type_ir",
+ "rustc_type_ir_macros",
  "smallvec",
  "tracing",
 ]
@@ -4833,10 +4683,21 @@
  "rustc_macros",
  "rustc_serialize",
  "rustc_span",
+ "rustc_type_ir_macros",
  "smallvec",
 ]
 
 [[package]]
+name = "rustc_type_ir_macros"
+version = "0.0.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.64",
+ "synstructure",
+]
+
+[[package]]
 name = "rustc_version"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -4930,7 +4791,7 @@
  "proc-macro2",
  "quote",
  "serde",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -4965,9 +4826,9 @@
 
 [[package]]
 name = "rustix"
-version = "0.38.32"
+version = "0.38.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65e04861e65f21776e67888bfbea442b3642beaa0138fdb1dd7a84a52dffdb89"
+checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
 dependencies = [
  "bitflags 2.5.0",
  "errno",
@@ -4977,19 +4838,10 @@
 ]
 
 [[package]]
-name = "rustls-pemfile"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
-dependencies = [
- "base64",
-]
-
-[[package]]
 name = "rustversion"
-version = "1.0.15"
+version = "1.0.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
+checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
 
 [[package]]
 name = "ruzstd"
@@ -5015,9 +4867,9 @@
 
 [[package]]
 name = "ryu"
-version = "1.0.17"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
 [[package]]
 name = "same-file"
@@ -5050,77 +4902,54 @@
 checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
-name = "security-framework"
-version = "2.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "770452e37cad93e0a50d5abc3990d2bc351c36d0328f86cefec2f2fb206eaef6"
-dependencies = [
- "bitflags 1.3.2",
- "core-foundation",
- "core-foundation-sys",
- "libc",
- "security-framework-sys",
-]
-
-[[package]]
-name = "security-framework-sys"
-version = "2.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41f3cc463c0ef97e11c3461a9d3787412d30e8e7eb907c79180c4a57bf7c04ef"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
 name = "self_cell"
 version = "0.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e14e4d63b804dc0c7ec4a1e52bcb63f02c7ac94476755aa579edac21e01f915d"
 dependencies = [
- "self_cell 1.0.3",
+ "self_cell 1.0.4",
 ]
 
 [[package]]
 name = "self_cell"
-version = "1.0.3"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "58bf37232d3bb9a2c4e641ca2a11d83b5062066f88df7fed36c28772046d65ba"
+checksum = "d369a96f978623eb3dc28807c4852d6cc617fed53da5d3c400feff1ef34a714a"
 
 [[package]]
 name = "semver"
-version = "1.0.22"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.197"
+version = "1.0.202"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
+checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.197"
+version = "1.0.202"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
+checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.115"
+version = "1.0.117"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
+checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
 dependencies = [
  "indexmap",
  "itoa",
@@ -5130,26 +4959,14 @@
 
 [[package]]
 name = "serde_spanned"
-version = "0.6.5"
+version = "0.6.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
+checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
 dependencies = [
  "serde",
 ]
 
 [[package]]
-name = "serde_urlencoded"
-version = "0.7.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
-dependencies = [
- "form_urlencoded",
- "itoa",
- "ryu",
- "serde",
-]
-
-[[package]]
 name = "sha1"
 version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5227,9 +5044,9 @@
 
 [[package]]
 name = "socket2"
-version = "0.5.6"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871"
+checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c"
 dependencies = [
  "libc",
  "windows-sys 0.52.0",
@@ -5375,12 +5192,6 @@
 
 [[package]]
 name = "strsim"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
-
-[[package]]
-name = "strsim"
 version = "0.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
@@ -5425,9 +5236,9 @@
 
 [[package]]
 name = "syn"
-version = "2.0.58"
+version = "2.0.64"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44cfb93f38070beee36b3fef7d4f5a16f27751d94b187b666a5cc5e9b0d30687"
+checksum = "7ad3dee41f36859875573074334c200d1add8e4a87bb37113ebd31d926b7b11f"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -5435,12 +5246,6 @@
 ]
 
 [[package]]
-name = "sync_wrapper"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
-
-[[package]]
 name = "synstructure"
 version = "0.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5448,14 +5253,14 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
 name = "sysinfo"
-version = "0.30.8"
+version = "0.30.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4b1a378e48fb3ce3a5cf04359c456c9c98ff689bcf1c1bc6e6a31f247686f275"
+checksum = "732ffa00f53e6b2af46208fba5718d9662a421049204e156328b66791ffa15ae"
 dependencies = [
  "cfg-if",
  "core-foundation-sys",
@@ -5475,27 +5280,6 @@
 ]
 
 [[package]]
-name = "system-configuration"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
-dependencies = [
- "bitflags 1.3.2",
- "core-foundation",
- "system-configuration-sys",
-]
-
-[[package]]
-name = "system-configuration-sys"
-version = "0.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
-dependencies = [
- "core-foundation-sys",
- "libc",
-]
-
-[[package]]
 name = "tabled"
 version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5599,22 +5383,22 @@
 
 [[package]]
 name = "thiserror"
-version = "1.0.58"
+version = "1.0.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
+checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.58"
+version = "1.0.61"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
+checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -5730,35 +5514,7 @@
 dependencies = [
  "backtrace",
  "bytes",
- "libc",
- "mio",
  "pin-project-lite",
- "socket2",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "tokio-native-tls"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
-dependencies = [
- "native-tls",
- "tokio",
-]
-
-[[package]]
-name = "tokio-util"
-version = "0.7.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
-dependencies = [
- "bytes",
- "futures-core",
- "futures-sink",
- "pin-project-lite",
- "tokio",
- "tracing",
 ]
 
 [[package]]
@@ -5784,9 +5540,9 @@
 
 [[package]]
 name = "toml_datetime"
-version = "0.6.5"
+version = "0.6.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
+checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
 dependencies = [
  "serde",
 ]
@@ -5811,12 +5567,6 @@
 checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d"
 
 [[package]]
-name = "tower-service"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
-
-[[package]]
 name = "tracing"
 version = "0.1.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5836,7 +5586,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -5902,12 +5652,6 @@
 ]
 
 [[package]]
-name = "try-lock"
-version = "0.2.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
-
-[[package]]
 name = "twox-hash"
 version = "1.6.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5920,9 +5664,9 @@
 
 [[package]]
 name = "type-map"
-version = "0.4.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6d3364c5e96cb2ad1603037ab253ddd34d7fb72a58bdddf4b7350760fc69a46"
+checksum = "deb68604048ff8fa93347f02441e4487594adc20bb8a084f9e564d2b827a0a9f"
 dependencies = [
  "rustc-hash",
 ]
@@ -6005,9 +5749,9 @@
 
 [[package]]
 name = "unic-langid"
-version = "0.9.4"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "238722e6d794ed130f91f4ea33e01fcff4f188d92337a21297892521c72df516"
+checksum = "23dd9d1e72a73b25e07123a80776aae3e7b0ec461ef94f9151eed6ec88005a44"
 dependencies = [
  "unic-langid-impl",
  "unic-langid-macros",
@@ -6015,18 +5759,18 @@
 
 [[package]]
 name = "unic-langid-impl"
-version = "0.9.4"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bd55a2063fdea4ef1f8633243a7b0524cbeef1905ae04c31a1c9b9775c55bc6"
+checksum = "0a5422c1f65949306c99240b81de9f3f15929f5a8bfe05bb44b034cc8bf593e5"
 dependencies = [
  "tinystr",
 ]
 
 [[package]]
 name = "unic-langid-macros"
-version = "0.9.4"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c854cefb82ff2816410ce606acbad1b3af065140907b29be9229040752b83ec"
+checksum = "0da1cd2c042d3c7569a1008806b02039e7a4a2bdf8f8e96bd3c792434a0e275e"
 dependencies = [
  "proc-macro-hack",
  "tinystr",
@@ -6036,13 +5780,13 @@
 
 [[package]]
 name = "unic-langid-macros-impl"
-version = "0.9.4"
+version = "0.9.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fea2a4c80deb4fb3ca51f66b5e2dd91e3642bbce52234bcf22e41668281208e4"
+checksum = "1ed7f4237ba393424195053097c1516bd4590dc82b84f2f97c5c69e12704555b"
 dependencies = [
  "proc-macro-hack",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
  "unic-langid-impl",
 ]
 
@@ -6113,9 +5857,9 @@
 
 [[package]]
 name = "unicode-width"
-version = "0.1.11"
+version = "0.1.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
+checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6"
 dependencies = [
  "compiler_builtins",
  "rustc-std-workspace-core",
@@ -6234,15 +5978,6 @@
 ]
 
 [[package]]
-name = "want"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
-dependencies = [
- "try-lock",
-]
-
-[[package]]
 name = "wasi"
 version = "0.11.0+wasi-snapshot-preview1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6274,23 +6009,11 @@
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
-name = "wasm-bindgen-futures"
-version = "0.4.42"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0"
-dependencies = [
- "cfg-if",
- "js-sys",
- "wasm-bindgen",
- "web-sys",
-]
-
-[[package]]
 name = "wasm-bindgen-macro"
 version = "0.2.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6308,7 +6031,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
@@ -6339,16 +6062,6 @@
 ]
 
 [[package]]
-name = "web-sys"
-version = "0.3.69"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
-dependencies = [
- "js-sys",
- "wasm-bindgen",
-]
-
-[[package]]
 name = "winapi"
 version = "0.3.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6366,11 +6079,11 @@
 
 [[package]]
 name = "winapi-util"
-version = "0.1.6"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
 dependencies = [
- "winapi",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -6386,7 +6099,7 @@
 checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be"
 dependencies = [
  "windows-core",
- "windows-targets 0.52.4",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
@@ -6399,7 +6112,7 @@
  "rayon",
  "serde",
  "serde_json",
- "syn 2.0.58",
+ "syn 2.0.64",
  "windows-metadata",
 ]
 
@@ -6409,7 +6122,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
 dependencies = [
- "windows-targets 0.52.4",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
@@ -6433,7 +6146,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.4",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
@@ -6453,17 +6166,18 @@
 
 [[package]]
 name = "windows-targets"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.4",
- "windows_aarch64_msvc 0.52.4",
- "windows_i686_gnu 0.52.4",
- "windows_i686_msvc 0.52.4",
- "windows_x86_64_gnu 0.52.4",
- "windows_x86_64_gnullvm 0.52.4",
- "windows_x86_64_msvc 0.52.4",
+ "windows_aarch64_gnullvm 0.52.5",
+ "windows_aarch64_msvc 0.52.5",
+ "windows_i686_gnu 0.52.5",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.5",
+ "windows_x86_64_gnu 0.52.5",
+ "windows_x86_64_gnullvm 0.52.5",
+ "windows_x86_64_msvc 0.52.5",
 ]
 
 [[package]]
@@ -6474,9 +6188,9 @@
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -6486,9 +6200,9 @@
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -6498,9 +6212,15 @@
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -6510,9 +6230,9 @@
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -6522,9 +6242,9 @@
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -6534,9 +6254,9 @@
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -6546,9 +6266,9 @@
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
 
 [[package]]
 name = "winnow"
@@ -6560,16 +6280,6 @@
 ]
 
 [[package]]
-name = "winreg"
-version = "0.50.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
-dependencies = [
- "cfg-if",
- "windows-sys 0.48.0",
-]
-
-[[package]]
 name = "writeable"
 version = "0.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6587,15 +6297,6 @@
 ]
 
 [[package]]
-name = "xz"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c887690ff2a2e233e8e49633461521f98ec57fbff9d59a884c9a4f04ec1da34"
-dependencies = [
- "xz2",
-]
-
-[[package]]
 name = "xz2"
 version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -6633,28 +6334,28 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
  "synstructure",
 ]
 
 [[package]]
 name = "zerocopy"
-version = "0.7.32"
+version = "0.7.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
+checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
 dependencies = [
  "zerocopy-derive",
 ]
 
 [[package]]
 name = "zerocopy-derive"
-version = "0.7.32"
+version = "0.7.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
+checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
 ]
 
 [[package]]
@@ -6674,7 +6375,7 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.58",
+ "syn 2.0.64",
  "synstructure",
 ]
 
@@ -6697,17 +6398,5 @@
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.58",
-]
-
-[[package]]
-name = "zip"
-version = "0.6.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261"
-dependencies = [
- "byteorder",
- "crc32fast",
- "crossbeam-utils",
- "flate2",
+ "syn 2.0.64",
 ]
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index 5e3f645..53aa8ad 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -926,6 +926,41 @@
     }
 }
 
+/// Floating-point types.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
+pub enum Float {
+    F16,
+    F32,
+    F64,
+    F128,
+}
+
+impl Float {
+    pub fn size(self) -> Size {
+        use Float::*;
+
+        match self {
+            F16 => Size::from_bits(16),
+            F32 => Size::from_bits(32),
+            F64 => Size::from_bits(64),
+            F128 => Size::from_bits(128),
+        }
+    }
+
+    pub fn align<C: HasDataLayout>(self, cx: &C) -> AbiAndPrefAlign {
+        use Float::*;
+        let dl = cx.data_layout();
+
+        match self {
+            F16 => dl.f16_align,
+            F32 => dl.f32_align,
+            F64 => dl.f64_align,
+            F128 => dl.f128_align,
+        }
+    }
+}
+
 /// Fundamental unit of memory access and layout.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
 #[cfg_attr(feature = "nightly", derive(HashStable_Generic))]
@@ -938,10 +973,7 @@
     /// a negative integer passed by zero-extension will appear positive in
     /// the callee, and most operations on it will produce the wrong values.
     Int(Integer, bool),
-    F16,
-    F32,
-    F64,
-    F128,
+    Float(Float),
     Pointer(AddressSpace),
 }
 
@@ -952,10 +984,7 @@
 
         match self {
             Int(i, _) => i.size(),
-            F16 => Size::from_bits(16),
-            F32 => Size::from_bits(32),
-            F64 => Size::from_bits(64),
-            F128 => Size::from_bits(128),
+            Float(f) => f.size(),
             // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
             // different address spaces can have different sizes
             // (but TargetDataLayout doesn't currently parse that part of the DL string)
@@ -969,10 +998,7 @@
 
         match self {
             Int(i, _) => i.align(dl),
-            F16 => dl.f16_align,
-            F32 => dl.f32_align,
-            F64 => dl.f64_align,
-            F128 => dl.f128_align,
+            Float(f) => f.align(dl),
             // FIXME(erikdesjardins): ignoring address space is technically wrong, pointers in
             // different address spaces can have different alignments
             // (but TargetDataLayout doesn't currently parse that part of the DL string)
@@ -1229,7 +1255,7 @@
 
     /// Gets source indices of the fields by increasing offsets.
     #[inline]
-    pub fn index_by_increasing_offset(&self) -> impl Iterator<Item = usize> + '_ {
+    pub fn index_by_increasing_offset(&self) -> impl ExactSizeIterator<Item = usize> + '_ {
         let mut inverse_small = [0u8; 64];
         let mut inverse_big = IndexVec::new();
         let use_small = self.count() <= inverse_small.len();
@@ -1245,7 +1271,12 @@
             }
         }
 
-        (0..self.count()).map(move |i| match *self {
+        // Primitives don't really have fields in the way that structs do,
+        // but having this return an empty iterator for them is unhelpful
+        // since that makes them look kinda like ZSTs, which they're not.
+        let pseudofield_count = if let FieldsShape::Primitive = self { 1 } else { self.count() };
+
+        (0..pseudofield_count).map(move |i| match *self {
             FieldsShape::Primitive | FieldsShape::Union(_) | FieldsShape::Array { .. } => i,
             FieldsShape::Arbitrary { .. } => {
                 if use_small {
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index fa378e1..1a16695 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -1422,7 +1422,7 @@
     /// of `if` / `while` expressions. (e.g., `if let 0 = x { .. }`).
     ///
     /// `Span` represents the whole `let pat = expr` statement.
-    Let(P<Pat>, P<Expr>, Span, Option<ErrorGuaranteed>),
+    Let(P<Pat>, P<Expr>, Span, Recovered),
     /// An `if` block, with an optional `else` block.
     ///
     /// `if expr { block } else { expr }`
@@ -2105,7 +2105,7 @@
 
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct BareFnTy {
-    pub unsafety: Unsafe,
+    pub safety: Safety,
     pub ext: Extern,
     pub generic_params: ThinVec<GenericParam>,
     pub decl: P<FnDecl>,
@@ -2164,7 +2164,7 @@
     MacCall(P<MacCall>),
     /// Placeholder for a `va_list`.
     CVarArgs,
-    /// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZeroU32`,
+    /// Pattern types like `pattern_type!(u32 is 1..=)`, which is the same as `NonZero<u32>`,
     /// just as part of the type system.
     Pat(P<Ty>, P<Pat>),
     /// Sometimes we need a dummy value when no error has occurred.
@@ -2484,11 +2484,15 @@
     No,
 }
 
+/// Safety of items.
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable, Debug)]
 #[derive(HashStable_Generic)]
-pub enum Unsafe {
-    Yes(Span),
-    No,
+pub enum Safety {
+    /// `unsafe` an item is explicitly marked as `unsafe`.
+    Unsafe(Span),
+    /// Default means no value was provided, it will take a default value given the context in
+    /// which is used.
+    Default,
 }
 
 /// Describes what kind of coroutine markers, if any, a function has.
@@ -2692,7 +2696,7 @@
 pub struct ForeignMod {
     /// `unsafe` keyword accepted syntactically for macro DSLs, but not
     /// semantically by Rust.
-    pub unsafety: Unsafe,
+    pub safety: Safety,
     pub abi: Option<StrLit>,
     pub items: ThinVec<P<ForeignItem>>,
 }
@@ -2729,7 +2733,14 @@
     /// `use prefix` or `use prefix as rename`
     Simple(Option<Ident>),
     /// `use prefix::{...}`
-    Nested(ThinVec<(UseTree, NodeId)>),
+    ///
+    /// The span represents the braces of the nested group and all elements within:
+    ///
+    /// ```text
+    /// use foo::{bar, baz};
+    ///          ^^^^^^^^^^
+    /// ```
+    Nested { items: ThinVec<(UseTree, NodeId)>, span: Span },
     /// `use prefix::*`
     Glob,
 }
@@ -2881,17 +2892,20 @@
     pub is_placeholder: bool,
 }
 
+/// Was parsing recovery performed?
+#[derive(Copy, Clone, Debug, Encodable, Decodable, HashStable_Generic)]
+pub enum Recovered {
+    No,
+    Yes(ErrorGuaranteed),
+}
+
 /// Fields and constructor ids of enum variants and structs.
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub enum VariantData {
     /// Struct variant.
     ///
     /// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
-    Struct {
-        fields: ThinVec<FieldDef>,
-        // FIXME: investigate making this a `Option<ErrorGuaranteed>`
-        recovered: bool,
-    },
+    Struct { fields: ThinVec<FieldDef>, recovered: Recovered },
     /// Tuple variant.
     ///
     /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`.
@@ -2958,6 +2972,7 @@
             | ItemKind::GlobalAsm(_)
             | ItemKind::MacCall(_)
             | ItemKind::Delegation(_)
+            | ItemKind::DelegationMac(_)
             | ItemKind::MacroDef(_) => None,
             ItemKind::Static(_) => None,
             ItemKind::Const(i) => Some(&i.generics),
@@ -3007,8 +3022,8 @@
 /// included in this struct (e.g., `async unsafe fn` or `const extern "C" fn`).
 #[derive(Clone, Copy, Encodable, Decodable, Debug)]
 pub struct FnHeader {
-    /// The `unsafe` keyword, if any
-    pub unsafety: Unsafe,
+    /// Whether this is `unsafe`, or has a default safety
+    pub safety: Safety,
     /// Whether this is `async`, `gen`, or nothing.
     pub coroutine_kind: Option<CoroutineKind>,
     /// The `const` keyword, if any
@@ -3020,8 +3035,8 @@
 impl FnHeader {
     /// Does this function header have any qualifiers or is it empty?
     pub fn has_qualifiers(&self) -> bool {
-        let Self { unsafety, coroutine_kind, constness, ext } = self;
-        matches!(unsafety, Unsafe::Yes(_))
+        let Self { safety, coroutine_kind, constness, ext } = self;
+        matches!(safety, Safety::Unsafe(_))
             || coroutine_kind.is_some()
             || matches!(constness, Const::Yes(_))
             || !matches!(ext, Extern::None)
@@ -3031,7 +3046,7 @@
 impl Default for FnHeader {
     fn default() -> FnHeader {
         FnHeader {
-            unsafety: Unsafe::No,
+            safety: Safety::Default,
             coroutine_kind: None,
             constness: Const::No,
             ext: Extern::None,
@@ -3041,7 +3056,7 @@
 
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Trait {
-    pub unsafety: Unsafe,
+    pub safety: Safety,
     pub is_auto: IsAuto,
     pub generics: Generics,
     pub bounds: GenericBounds,
@@ -3097,7 +3112,7 @@
 #[derive(Clone, Encodable, Decodable, Debug)]
 pub struct Impl {
     pub defaultness: Defaultness,
-    pub unsafety: Unsafe,
+    pub safety: Safety,
     pub generics: Generics,
     pub constness: Const,
     pub polarity: ImplPolarity,
@@ -3120,8 +3135,16 @@
     /// Path resolution id.
     pub id: NodeId,
     pub qself: Option<P<QSelf>>,
-    pub rename: Option<Ident>,
     pub path: Path,
+    pub rename: Option<Ident>,
+    pub body: Option<P<Block>>,
+}
+
+#[derive(Clone, Encodable, Decodable, Debug)]
+pub struct DelegationMac {
+    pub qself: Option<P<QSelf>>,
+    pub prefix: Path,
+    pub suffixes: ThinVec<(Ident, Option<Ident>)>,
     pub body: Option<P<Block>>,
 }
 
@@ -3197,7 +3220,7 @@
     /// E.g., `mod foo;` or `mod foo { .. }`.
     /// `unsafe` keyword on modules is accepted syntactically for macro DSLs, but not
     /// semantically by Rust.
-    Mod(Unsafe, ModKind),
+    Mod(Safety, ModKind),
     /// An external module (`extern`).
     ///
     /// E.g., `extern {}` or `extern "C" {}`.
@@ -3240,19 +3263,23 @@
     /// A macro definition.
     MacroDef(MacroDef),
 
-    /// A delegation item (`reuse`).
+    /// A single delegation item (`reuse`).
     ///
     /// E.g. `reuse <Type as Trait>::name { target_expr_template }`.
     Delegation(Box<Delegation>),
+    /// A list delegation item (`reuse prefix::{a, b, c}`).
+    /// Treated similarly to a macro call and expanded early.
+    DelegationMac(Box<DelegationMac>),
 }
 
 impl ItemKind {
+    /// "a" or "an"
     pub fn article(&self) -> &'static str {
         use ItemKind::*;
         match self {
             Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
             | Struct(..) | Union(..) | Trait(..) | TraitAlias(..) | MacroDef(..)
-            | Delegation(..) => "a",
+            | Delegation(..) | DelegationMac(..) => "a",
             ExternCrate(..) | ForeignMod(..) | MacCall(..) | Enum(..) | Impl { .. } => "an",
         }
     }
@@ -3277,6 +3304,7 @@
             ItemKind::MacroDef(..) => "macro definition",
             ItemKind::Impl { .. } => "implementation",
             ItemKind::Delegation(..) => "delegated function",
+            ItemKind::DelegationMac(..) => "delegation",
         }
     }
 
@@ -3320,6 +3348,8 @@
     MacCall(P<MacCall>),
     /// An associated delegation item.
     Delegation(Box<Delegation>),
+    /// An associated delegation item list.
+    DelegationMac(Box<DelegationMac>),
 }
 
 impl AssocItemKind {
@@ -3328,7 +3358,9 @@
             Self::Const(box ConstItem { defaultness, .. })
             | Self::Fn(box Fn { defaultness, .. })
             | Self::Type(box TyAlias { defaultness, .. }) => defaultness,
-            Self::MacCall(..) | Self::Delegation(..) => Defaultness::Final,
+            Self::MacCall(..) | Self::Delegation(..) | Self::DelegationMac(..) => {
+                Defaultness::Final
+            }
         }
     }
 }
@@ -3341,6 +3373,7 @@
             AssocItemKind::Type(ty_alias_kind) => ItemKind::TyAlias(ty_alias_kind),
             AssocItemKind::MacCall(a) => ItemKind::MacCall(a),
             AssocItemKind::Delegation(delegation) => ItemKind::Delegation(delegation),
+            AssocItemKind::DelegationMac(delegation) => ItemKind::DelegationMac(delegation),
         }
     }
 }
@@ -3355,6 +3388,7 @@
             ItemKind::TyAlias(ty_kind) => AssocItemKind::Type(ty_kind),
             ItemKind::MacCall(a) => AssocItemKind::MacCall(a),
             ItemKind::Delegation(d) => AssocItemKind::Delegation(d),
+            ItemKind::DelegationMac(d) => AssocItemKind::DelegationMac(d),
             _ => return Err(item_kind),
         })
     }
diff --git a/compiler/rustc_ast/src/ast_traits.rs b/compiler/rustc_ast/src/ast_traits.rs
index a048622..2cf811e 100644
--- a/compiler/rustc_ast/src/ast_traits.rs
+++ b/compiler/rustc_ast/src/ast_traits.rs
@@ -240,7 +240,6 @@
             Nonterminal::NtPath(path) => path.tokens(),
             Nonterminal::NtVis(vis) => vis.tokens(),
             Nonterminal::NtBlock(block) => block.tokens(),
-            Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
         }
     }
     fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
@@ -254,7 +253,6 @@
             Nonterminal::NtPath(path) => path.tokens_mut(),
             Nonterminal::NtVis(vis) => vis.tokens_mut(),
             Nonterminal::NtBlock(block) => block.tokens_mut(),
-            Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
         }
     }
 }
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index 0f12fd3..d5c9fc9 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -13,6 +13,7 @@
 use rustc_index::bit_set::GrowableBitSet;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::Span;
+use smallvec::{smallvec, SmallVec};
 use std::iter;
 use std::sync::atomic::{AtomicU32, Ordering};
 use thin_vec::{thin_vec, ThinVec};
@@ -87,10 +88,20 @@
             AttrKind::DocComment(..) => None,
         }
     }
+
     pub fn name_or_empty(&self) -> Symbol {
         self.ident().unwrap_or_else(Ident::empty).name
     }
 
+    pub fn path(&self) -> SmallVec<[Symbol; 1]> {
+        match &self.kind {
+            AttrKind::Normal(normal) => {
+                normal.item.path.segments.iter().map(|s| s.ident.name).collect()
+            }
+            AttrKind::DocComment(..) => smallvec![sym::doc],
+        }
+    }
+
     #[inline]
     pub fn has_name(&self, name: Symbol) -> bool {
         match &self.kind {
@@ -345,7 +356,7 @@
                 let span = span.with_hi(segments.last().unwrap().ident.span.hi());
                 Path { span, segments, tokens: None }
             }
-            Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &nt.0 {
+            Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &**nt {
                 token::Nonterminal::NtMeta(item) => return item.meta(item.path.span),
                 token::Nonterminal::NtPath(path) => (**path).clone(),
                 _ => return None,
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 4d28ef5..566b20c 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -441,7 +441,7 @@
     vis.visit_path(prefix);
     match kind {
         UseTreeKind::Simple(rename) => visit_opt(rename, |rename| vis.visit_ident(rename)),
-        UseTreeKind::Nested(items) => {
+        UseTreeKind::Nested { items, .. } => {
             for (tree, id) in items {
                 vis.visit_use_tree(tree);
                 vis.visit_id(id);
@@ -499,8 +499,8 @@
             vis.visit_mt(mt);
         }
         TyKind::BareFn(bft) => {
-            let BareFnTy { unsafety, ext: _, generic_params, decl, decl_span } = bft.deref_mut();
-            visit_unsafety(unsafety, vis);
+            let BareFnTy { safety, ext: _, generic_params, decl, decl_span } = bft.deref_mut();
+            visit_safety(safety, vis);
             generic_params.flat_map_in_place(|param| vis.flat_map_generic_param(param));
             vis.visit_fn_decl(decl);
             vis.visit_span(decl_span);
@@ -543,8 +543,8 @@
 }
 
 fn noop_visit_foreign_mod<T: MutVisitor>(foreign_mod: &mut ForeignMod, vis: &mut T) {
-    let ForeignMod { unsafety, abi: _, items } = foreign_mod;
-    visit_unsafety(unsafety, vis);
+    let ForeignMod { safety, abi: _, items } = foreign_mod;
+    visit_safety(safety, vis);
     items.flat_map_in_place(|item| vis.flat_map_foreign_item(item));
 }
 
@@ -781,10 +781,14 @@
             *span = ident.span;
             return; // Avoid visiting the span for the second time.
         }
+        token::NtIdent(ident, _is_raw) => {
+            vis.visit_ident(ident);
+        }
+        token::NtLifetime(ident) => {
+            vis.visit_ident(ident);
+        }
         token::Interpolated(nt) => {
             let nt = Lrc::make_mut(nt);
-            let (nt, sp) = (&mut nt.0, &mut nt.1);
-            vis.visit_span(sp);
             visit_nonterminal(nt, vis);
         }
         _ => {}
@@ -834,8 +838,6 @@
         token::NtPat(pat) => vis.visit_pat(pat),
         token::NtExpr(expr) => vis.visit_expr(expr),
         token::NtTy(ty) => vis.visit_ty(ty),
-        token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
-        token::NtLifetime(ident) => vis.visit_ident(ident),
         token::NtLiteral(expr) => vis.visit_expr(expr),
         token::NtMeta(item) => {
             let AttrItem { path, args, tokens } = item.deref_mut();
@@ -857,10 +859,10 @@
 }
 
 // No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
-fn visit_unsafety<T: MutVisitor>(unsafety: &mut Unsafe, vis: &mut T) {
-    match unsafety {
-        Unsafe::Yes(span) => vis.visit_span(span),
-        Unsafe::No => {}
+fn visit_safety<T: MutVisitor>(safety: &mut Safety, vis: &mut T) {
+    match safety {
+        Safety::Unsafe(span) => vis.visit_span(span),
+        Safety::Default => {}
     }
 }
 
@@ -1090,8 +1092,8 @@
                 vis.visit_generics(generics);
                 visit_opt(body, |body| vis.visit_block(body));
             }
-            ItemKind::Mod(unsafety, mod_kind) => {
-                visit_unsafety(unsafety, vis);
+            ItemKind::Mod(safety, mod_kind) => {
+                visit_safety(safety, vis);
                 match mod_kind {
                     ModKind::Loaded(items, _inline, ModSpans { inner_span, inject_use_span }) => {
                         vis.visit_span(inner_span);
@@ -1128,7 +1130,7 @@
             }
             ItemKind::Impl(box Impl {
                 defaultness,
-                unsafety,
+                safety,
                 generics,
                 constness,
                 polarity,
@@ -1137,7 +1139,7 @@
                 items,
             }) => {
                 visit_defaultness(defaultness, vis);
-                visit_unsafety(unsafety, vis);
+                visit_safety(safety, vis);
                 vis.visit_generics(generics);
                 visit_constness(constness, vis);
                 visit_polarity(polarity, vis);
@@ -1145,8 +1147,8 @@
                 vis.visit_ty(self_ty);
                 items.flat_map_in_place(|item| vis.flat_map_impl_item(item));
             }
-            ItemKind::Trait(box Trait { unsafety, is_auto: _, generics, bounds, items }) => {
-                visit_unsafety(unsafety, vis);
+            ItemKind::Trait(box Trait { safety, is_auto: _, generics, bounds, items }) => {
+                visit_safety(safety, vis);
                 vis.visit_generics(generics);
                 visit_bounds(bounds, vis);
                 items.flat_map_in_place(|item| vis.flat_map_trait_item(item));
@@ -1168,6 +1170,19 @@
                     vis.visit_block(body);
                 }
             }
+            ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
+                vis.visit_qself(qself);
+                vis.visit_path(prefix);
+                for (ident, rename) in suffixes {
+                    vis.visit_ident(ident);
+                    if let Some(rename) = rename {
+                        vis.visit_ident(rename);
+                    }
+                }
+                if let Some(body) = body {
+                    vis.visit_block(body);
+                }
+            }
         }
     }
 }
@@ -1211,6 +1226,19 @@
                     visitor.visit_block(body);
                 }
             }
+            AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
+                visitor.visit_qself(qself);
+                visitor.visit_path(prefix);
+                for (ident, rename) in suffixes {
+                    visitor.visit_ident(ident);
+                    if let Some(rename) = rename {
+                        visitor.visit_ident(rename);
+                    }
+                }
+                if let Some(body) = body {
+                    visitor.visit_block(body);
+                }
+            }
         }
     }
 }
@@ -1226,10 +1254,10 @@
 }
 
 fn noop_visit_fn_header<T: MutVisitor>(header: &mut FnHeader, vis: &mut T) {
-    let FnHeader { unsafety, coroutine_kind, constness, ext: _ } = header;
+    let FnHeader { safety, coroutine_kind, constness, ext: _ } = header;
     visit_constness(constness, vis);
     coroutine_kind.as_mut().map(|coroutine_kind| vis.visit_coroutine_kind(coroutine_kind));
-    visit_unsafety(unsafety, vis);
+    visit_safety(safety, vis);
 }
 
 pub fn noop_visit_crate<T: MutVisitor>(krate: &mut Crate, vis: &mut T) {
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
index e22a523..34c539e 100644
--- a/compiler/rustc_ast/src/ptr.rs
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -184,7 +184,7 @@
     type Item = &'a T;
     type IntoIter = slice::Iter<'a, T>;
     fn into_iter(self) -> Self::IntoIter {
-        self.ptr.into_iter()
+        self.ptr.iter()
     }
 }
 
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index 72f8973..099a609 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -111,7 +111,7 @@
             Ident(name, IdentIsRaw::No) if name.is_bool_lit() => Some(Lit::new(Bool, name, None)),
             Literal(token_lit) => Some(token_lit),
             Interpolated(ref nt)
-                if let NtExpr(expr) | NtLiteral(expr) = &nt.0
+                if let NtExpr(expr) | NtLiteral(expr) = &**nt
                     && let ast::ExprKind::Lit(token_lit) = expr.kind =>
             {
                 Some(token_lit)
@@ -318,11 +318,20 @@
     /// It's recommended to use `Token::(ident,uninterpolate,uninterpolated_span)` to
     /// treat regular and interpolated identifiers in the same way.
     Ident(Symbol, IdentIsRaw),
+    /// This identifier (and its span) is the identifier passed to the
+    /// declarative macro. The span in the surrounding `Token` is the span of
+    /// the `ident` metavariable in the macro's RHS.
+    NtIdent(Ident, IdentIsRaw),
+
     /// Lifetime identifier token.
     /// Do not forget about `NtLifetime` when you want to match on lifetime identifiers.
     /// It's recommended to use `Token::(lifetime,uninterpolate,uninterpolated_span)` to
     /// treat regular and interpolated lifetime identifiers in the same way.
     Lifetime(Symbol),
+    /// This identifier (and its span) is the lifetime passed to the
+    /// declarative macro. The span in the surrounding `Token` is the span of
+    /// the `lifetime` metavariable in the macro's RHS.
+    NtLifetime(Ident),
 
     /// An embedded AST node, as produced by a macro. This only exists for
     /// historical reasons. We'd like to get rid of it, for multiple reasons.
@@ -333,7 +342,11 @@
     /// - It prevents `Token` from implementing `Copy`.
     /// It adds complexity and likely slows things down. Please don't add new
     /// occurrences of this token kind!
-    Interpolated(Lrc<(Nonterminal, Span)>),
+    ///
+    /// The span in the surrounding `Token` is that of the metavariable in the
+    /// macro's RHS. The span within the Nonterminal is that of the fragment
+    /// passed to the macro at the call site.
+    Interpolated(Lrc<Nonterminal>),
 
     /// A doc comment token.
     /// `Symbol` is the doc comment's data excluding its "quotes" (`///`, `/**`, etc)
@@ -440,8 +453,9 @@
     /// Note that keywords are also identifiers, so they should use this
     /// if they keep spans or perform edition checks.
     pub fn uninterpolated_span(&self) -> Span {
-        match &self.kind {
-            Interpolated(nt) => nt.0.use_span(),
+        match self.kind {
+            NtIdent(ident, _) | NtLifetime(ident) => ident.span,
+            Interpolated(ref nt) => nt.use_span(),
             _ => self.span,
         }
     }
@@ -459,7 +473,7 @@
             }
 
             OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..)
-            | Lifetime(..) | Interpolated(..) | Eof => false,
+            | NtIdent(..) | Lifetime(..) | NtLifetime(..) | Interpolated(..) | Eof => false,
         }
     }
 
@@ -486,7 +500,7 @@
             PathSep                            | // global path
             Lifetime(..)                      | // labeled loop
             Pound                             => true, // expression attributes
-            Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
+            Interpolated(ref nt) => matches!(&**nt, NtLiteral(..) |
                 NtExpr(..)    |
                 NtBlock(..)   |
                 NtPath(..)),
@@ -510,7 +524,7 @@
             | DotDot | DotDotDot | DotDotEq      // ranges
             | Lt | BinOp(Shl)                    // associated path
             | PathSep                    => true, // global path
-            Interpolated(ref nt) => matches!(&nt.0, NtLiteral(..) |
+            Interpolated(ref nt) => matches!(&**nt, NtLiteral(..) |
                 NtPat(..)     |
                 NtBlock(..)   |
                 NtPath(..)),
@@ -533,7 +547,7 @@
             Lifetime(..)                | // lifetime bound in trait object
             Lt | BinOp(Shl)             | // associated path
             PathSep                      => true, // global path
-            Interpolated(ref nt) => matches!(&nt.0, NtTy(..) | NtPath(..)),
+            Interpolated(ref nt) => matches!(&**nt, NtTy(..) | NtPath(..)),
             // For anonymous structs or unions, which only appear in specific positions
             // (type of struct fields or union fields), we don't consider them as regular types
             _ => false,
@@ -544,7 +558,7 @@
     pub fn can_begin_const_arg(&self) -> bool {
         match self.kind {
             OpenDelim(Delimiter::Brace) => true,
-            Interpolated(ref nt) => matches!(&nt.0, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
+            Interpolated(ref nt) => matches!(&**nt, NtExpr(..) | NtBlock(..) | NtLiteral(..)),
             _ => self.can_begin_literal_maybe_minus(),
         }
     }
@@ -589,7 +603,7 @@
         match self.uninterpolate().kind {
             Literal(..) | BinOp(Minus) => true,
             Ident(name, IdentIsRaw::No) if name.is_bool_lit() => true,
-            Interpolated(ref nt) => match &nt.0 {
+            Interpolated(ref nt) => match &**nt {
                 NtLiteral(_) => true,
                 NtExpr(e) => match &e.kind {
                     ast::ExprKind::Lit(_) => true,
@@ -609,14 +623,9 @@
     /// into the regular identifier or lifetime token it refers to,
     /// otherwise returns the original token.
     pub fn uninterpolate(&self) -> Cow<'_, Token> {
-        match &self.kind {
-            Interpolated(nt) => match &nt.0 {
-                NtIdent(ident, is_raw) => {
-                    Cow::Owned(Token::new(Ident(ident.name, *is_raw), ident.span))
-                }
-                NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
-                _ => Cow::Borrowed(self),
-            },
+        match self.kind {
+            NtIdent(ident, is_raw) => Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span)),
+            NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
             _ => Cow::Borrowed(self),
         }
     }
@@ -625,12 +634,9 @@
     #[inline]
     pub fn ident(&self) -> Option<(Ident, IdentIsRaw)> {
         // We avoid using `Token::uninterpolate` here because it's slow.
-        match &self.kind {
-            &Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
-            Interpolated(nt) => match &nt.0 {
-                NtIdent(ident, is_raw) => Some((*ident, *is_raw)),
-                _ => None,
-            },
+        match self.kind {
+            Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
+            NtIdent(ident, is_raw) => Some((ident, is_raw)),
             _ => None,
         }
     }
@@ -639,12 +645,9 @@
     #[inline]
     pub fn lifetime(&self) -> Option<Ident> {
         // We avoid using `Token::uninterpolate` here because it's slow.
-        match &self.kind {
-            &Lifetime(name) => Some(Ident::new(name, self.span)),
-            Interpolated(nt) => match &nt.0 {
-                NtLifetime(ident) => Some(*ident),
-                _ => None,
-            },
+        match self.kind {
+            Lifetime(name) => Some(Ident::new(name, self.span)),
+            NtLifetime(ident) => Some(ident),
             _ => None,
         }
     }
@@ -668,7 +671,7 @@
     /// Returns `true` if the token is an interpolated path.
     fn is_whole_path(&self) -> bool {
         if let Interpolated(nt) = &self.kind
-            && let NtPath(..) = &nt.0
+            && let NtPath(..) = &**nt
         {
             return true;
         }
@@ -681,7 +684,7 @@
     /// (which happens while parsing the result of macro expansion)?
     pub fn is_whole_expr(&self) -> bool {
         if let Interpolated(nt) = &self.kind
-            && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &nt.0
+            && let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = &**nt
         {
             return true;
         }
@@ -692,7 +695,7 @@
     /// Is the token an interpolated block (`$b:block`)?
     pub fn is_whole_block(&self) -> bool {
         if let Interpolated(nt) = &self.kind
-            && let NtBlock(..) = &nt.0
+            && let NtBlock(..) = &**nt
         {
             return true;
         }
@@ -833,8 +836,10 @@
 
             Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot
             | DotDotEq | Comma | Semi | PathSep | RArrow | LArrow | FatArrow | Pound | Dollar
-            | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..)
-            | Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None,
+            | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) | NtIdent(..)
+            | Lifetime(..) | NtLifetime(..) | Interpolated(..) | DocComment(..) | Eof => {
+                return None;
+            }
         };
 
         Some(Token::new(kind, self.span.to(joint.span)))
@@ -857,8 +862,6 @@
     NtPat(P<ast::Pat>),
     NtExpr(P<ast::Expr>),
     NtTy(P<ast::Ty>),
-    NtIdent(Ident, IdentIsRaw),
-    NtLifetime(Ident),
     NtLiteral(P<ast::Expr>),
     /// Stuff inside brackets for attributes
     NtMeta(P<ast::AttrItem>),
@@ -878,6 +881,8 @@
     },
     PatWithOr,
     Expr,
+    /// Matches an expression using the rules from edition 2021 and earlier.
+    Expr2021,
     Ty,
     Ident,
     Lifetime,
@@ -907,6 +912,7 @@
             },
             sym::pat_param => NonterminalKind::PatParam { inferred: false },
             sym::expr => NonterminalKind::Expr,
+            sym::expr_2021 if edition().at_least_rust_2021() => NonterminalKind::Expr2021,
             sym::ty => NonterminalKind::Ty,
             sym::ident => NonterminalKind::Ident,
             sym::lifetime => NonterminalKind::Lifetime,
@@ -926,6 +932,7 @@
             NonterminalKind::PatParam { inferred: false } => sym::pat_param,
             NonterminalKind::PatParam { inferred: true } | NonterminalKind::PatWithOr => sym::pat,
             NonterminalKind::Expr => sym::expr,
+            NonterminalKind::Expr2021 => sym::expr_2021,
             NonterminalKind::Ty => sym::ty,
             NonterminalKind::Ident => sym::ident,
             NonterminalKind::Lifetime => sym::lifetime,
@@ -953,7 +960,6 @@
             NtPat(pat) => pat.span,
             NtExpr(expr) | NtLiteral(expr) => expr.span,
             NtTy(ty) => ty.span,
-            NtIdent(ident, _) | NtLifetime(ident) => ident.span,
             NtMeta(attr_item) => attr_item.span(),
             NtPath(path) => path.span,
             NtVis(vis) => vis.span,
@@ -969,8 +975,6 @@
             NtExpr(..) => "expression",
             NtLiteral(..) => "literal",
             NtTy(..) => "type",
-            NtIdent(..) => "identifier",
-            NtLifetime(..) => "lifetime",
             NtMeta(..) => "attribute",
             NtPath(..) => "path",
             NtVis(..) => "visibility",
@@ -979,18 +983,12 @@
 }
 
 impl PartialEq for Nonterminal {
-    fn eq(&self, rhs: &Self) -> bool {
-        match (self, rhs) {
-            (NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => {
-                ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
-            }
-            (NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
-            // FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
-            // correctly based on data from AST. This will prevent them from matching each other
-            // in macros. The comparison will become possible only when each nonterminal has an
-            // attached token stream from which it was parsed.
-            _ => false,
-        }
+    fn eq(&self, _rhs: &Self) -> bool {
+        // FIXME: Assume that all nonterminals are not equal, we can't compare them
+        // correctly based on data from AST. This will prevent them from matching each other
+        // in macros. The comparison will become possible only when each nonterminal has an
+        // attached token stream from which it was parsed.
+        false
     }
 }
 
@@ -1003,12 +1001,10 @@
             NtPat(..) => f.pad("NtPat(..)"),
             NtExpr(..) => f.pad("NtExpr(..)"),
             NtTy(..) => f.pad("NtTy(..)"),
-            NtIdent(..) => f.pad("NtIdent(..)"),
             NtLiteral(..) => f.pad("NtLiteral(..)"),
             NtMeta(..) => f.pad("NtMeta(..)"),
             NtPath(..) => f.pad("NtPath(..)"),
             NtVis(..) => f.pad("NtVis(..)"),
-            NtLifetime(..) => f.pad("NtLifetime(..)"),
         }
     }
 }
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index 8e80161..fb66655 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -466,12 +466,6 @@
 
     pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
         match nt {
-            Nonterminal::NtIdent(ident, is_raw) => {
-                TokenStream::token_alone(token::Ident(ident.name, *is_raw), ident.span)
-            }
-            Nonterminal::NtLifetime(ident) => {
-                TokenStream::token_alone(token::Lifetime(ident.name), ident.span)
-            }
             Nonterminal::NtItem(item) => TokenStream::from_ast(item),
             Nonterminal::NtBlock(block) => TokenStream::from_ast(block),
             Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => {
@@ -489,15 +483,21 @@
     }
 
     fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
-        match &token.kind {
-            token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = nt.0 => {
+        match token.kind {
+            token::NtIdent(ident, is_raw) => {
                 TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
             }
-            token::Interpolated(nt) => TokenTree::Delimited(
+            token::NtLifetime(ident) => TokenTree::Delimited(
                 DelimSpan::from_single(token.span),
                 DelimSpacing::new(Spacing::JointHidden, spacing),
                 Delimiter::Invisible,
-                TokenStream::from_nonterminal_ast(&nt.0).flattened(),
+                TokenStream::token_alone(token::Lifetime(ident.name), ident.span),
+            ),
+            token::Interpolated(ref nt) => TokenTree::Delimited(
+                DelimSpan::from_single(token.span),
+                DelimSpacing::new(Spacing::JointHidden, spacing),
+                Delimiter::Invisible,
+                TokenStream::from_nonterminal_ast(&nt).flattened(),
             ),
             _ => TokenTree::Token(token.clone(), spacing),
         }
@@ -516,7 +516,10 @@
     pub fn flattened(&self) -> TokenStream {
         fn can_skip(stream: &TokenStream) -> bool {
             stream.trees().all(|tree| match tree {
-                TokenTree::Token(token, _) => !matches!(token.kind, token::Interpolated(_)),
+                TokenTree::Token(token, _) => !matches!(
+                    token.kind,
+                    token::NtIdent(..) | token::NtLifetime(..) | token::Interpolated(..)
+                ),
                 TokenTree::Delimited(.., inner) => can_skip(inner),
             })
         }
diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs
index f21a9ca..f6e9e1a 100644
--- a/compiler/rustc_ast/src/util/classify.rs
+++ b/compiler/rustc_ast/src/util/classify.rs
@@ -1,34 +1,88 @@
-//! Routines the parser uses to classify AST nodes
+//! Routines the parser and pretty-printer use to classify AST nodes.
 
-// Predicates on exprs and stmts that the pretty-printer and parser use
-
+use crate::ast::ExprKind::*;
 use crate::{ast, token::Delimiter};
 
-/// Does this expression require a semicolon to be treated
-/// as a statement? The negation of this: 'can this expression
-/// be used as a statement without a semicolon' -- is used
-/// as an early-bail-out in the parser so that, for instance,
-///     if true {...} else {...}
-///      |x| 5
-/// isn't parsed as (if true {...} else {...} | x) | 5
-pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
-    !matches!(
+/// This classification determines whether various syntactic positions break out
+/// of parsing the current expression (true) or continue parsing more of the
+/// same expression (false).
+///
+/// For example, it's relevant in the parsing of match arms:
+///
+/// ```ignore (illustrative)
+/// match ... {
+///     // Is this calling $e as a function, or is it the start of a new arm
+///     // with a tuple pattern?
+///     _ => $e (
+///             ^                                                          )
+///
+///     // Is this an Index operation, or new arm with a slice pattern?
+///     _ => $e [
+///             ^                                                          ]
+///
+///     // Is this a binary operator, or leading vert in a new arm? Same for
+///     // other punctuation which can either be a binary operator in
+///     // expression or unary operator in pattern, such as `&` and `-`.
+///     _ => $e |
+///             ^
+/// }
+/// ```
+///
+/// If $e is something like `{}` or `if … {}`, then terminate the current
+/// arm and parse a new arm.
+///
+/// If $e is something like `path::to` or `(…)`, continue parsing the same
+/// arm.
+///
+/// *Almost* the same classification is used as an early bail-out for parsing
+/// statements. See `expr_requires_semi_to_be_stmt`.
+pub fn expr_is_complete(e: &ast::Expr) -> bool {
+    matches!(
         e.kind,
-        ast::ExprKind::If(..)
-            | ast::ExprKind::Match(..)
-            | ast::ExprKind::Block(..)
-            | ast::ExprKind::While(..)
-            | ast::ExprKind::Loop(..)
-            | ast::ExprKind::ForLoop { .. }
-            | ast::ExprKind::TryBlock(..)
-            | ast::ExprKind::ConstBlock(..)
+        If(..)
+            | Match(..)
+            | Block(..)
+            | While(..)
+            | Loop(..)
+            | ForLoop { .. }
+            | TryBlock(..)
+            | ConstBlock(..)
     )
 }
 
+/// Does this expression require a semicolon to be treated as a statement?
+///
+/// The negation of this: "can this expression be used as a statement without a
+/// semicolon" -- is used as an early bail-out when parsing statements so that,
+/// for instance,
+///
+/// ```ignore (illustrative)
+/// if true {...} else {...}
+/// |x| 5
+/// ```
+///
+/// isn't parsed as `(if true {...} else {...} | x) | 5`.
+///
+/// Surprising special case: even though braced macro calls like `m! {}`
+/// normally do not introduce a boundary when found at the head of a match arm,
+/// they do terminate the parsing of a statement.
+///
+/// ```ignore (illustrative)
+/// match ... {
+///     _ => m! {} (),  // macro that expands to a function, which is then called
+/// }
+///
+/// let _ = { m! {} () };  // macro call followed by unit
+/// ```
+pub fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
+    match &e.kind {
+        MacCall(mac_call) => mac_call.args.delim != Delimiter::Brace,
+        _ => !expr_is_complete(e),
+    }
+}
+
 /// If an expression ends with `}`, returns the innermost expression ending in the `}`
 pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> {
-    use ast::ExprKind::*;
-
     loop {
         match &expr.kind {
             AddrOf(_, _, e)
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 1d8fd63..93de42b 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -366,7 +366,7 @@
             }
             ItemKind::Impl(box Impl {
                 defaultness: _,
-                unsafety: _,
+                safety: _,
                 generics,
                 constness: _,
                 polarity: _,
@@ -384,7 +384,7 @@
                 try_visit!(visitor.visit_generics(generics));
                 try_visit!(visitor.visit_variant_data(struct_definition));
             }
-            ItemKind::Trait(box Trait { unsafety: _, is_auto: _, generics, bounds, items }) => {
+            ItemKind::Trait(box Trait { safety: _, is_auto: _, generics, bounds, items }) => {
                 try_visit!(visitor.visit_generics(generics));
                 walk_list!(visitor, visit_param_bound, bounds, BoundKind::SuperTraits);
                 walk_list!(visitor, visit_assoc_item, items, AssocCtxt::Trait);
@@ -403,6 +403,19 @@
                 visit_opt!(visitor, visit_ident, *rename);
                 visit_opt!(visitor, visit_block, body);
             }
+            ItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
+                if let Some(qself) = qself {
+                    try_visit!(visitor.visit_ty(&qself.ty));
+                }
+                try_visit!(visitor.visit_path(prefix, item.id));
+                for (ident, rename) in suffixes {
+                    visitor.visit_ident(*ident);
+                    if let Some(rename) = rename {
+                        visitor.visit_ident(*rename);
+                    }
+                }
+                visit_opt!(visitor, visit_block, body);
+            }
         }
         V::Result::output()
     }
@@ -517,8 +530,8 @@
             visit_opt!(visitor, visit_ident, rename);
         }
         UseTreeKind::Glob => {}
-        UseTreeKind::Nested(ref use_trees) => {
-            for &(ref nested_tree, nested_id) in use_trees {
+        UseTreeKind::Nested { ref items, .. } => {
+            for &(ref nested_tree, nested_id) in items {
                 try_visit!(visitor.visit_use_tree(nested_tree, nested_id, true));
             }
         }
@@ -815,6 +828,19 @@
                 visit_opt!(visitor, visit_ident, *rename);
                 visit_opt!(visitor, visit_block, body);
             }
+            AssocItemKind::DelegationMac(box DelegationMac { qself, prefix, suffixes, body }) => {
+                if let Some(qself) = qself {
+                    try_visit!(visitor.visit_ty(&qself.ty));
+                }
+                try_visit!(visitor.visit_path(prefix, item.id));
+                for (ident, rename) in suffixes {
+                    visitor.visit_ident(*ident);
+                    if let Some(rename) = rename {
+                        visitor.visit_ident(*rename);
+                    }
+                }
+                visit_opt!(visitor, visit_block, body);
+            }
         }
         V::Result::output()
     }
diff --git a/compiler/rustc_ast_lowering/src/delegation.rs b/compiler/rustc_ast_lowering/src/delegation.rs
index a1e5c27..27f8a6e 100644
--- a/compiler/rustc_ast_lowering/src/delegation.rs
+++ b/compiler/rustc_ast_lowering/src/delegation.rs
@@ -188,7 +188,7 @@
                 Asyncness::No => hir::IsAsync::NotAsync,
             };
             hir::FnHeader {
-                unsafety: sig.unsafety,
+                safety: sig.safety,
                 constness: self.tcx.constness(sig_id),
                 asyncness,
                 abi: sig.abi,
@@ -341,7 +341,7 @@
 
     fn generate_header_error(&self) -> hir::FnHeader {
         hir::FnHeader {
-            unsafety: hir::Unsafety::Normal,
+            safety: hir::Safety::Safe,
             constness: hir::Constness::NotConst,
             asyncness: hir::IsAsync::NotAsync,
             abi: abi::Abi::Rust,
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 443b596..a553109 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -158,13 +158,13 @@
                     let ohs = self.lower_expr(ohs);
                     hir::ExprKind::AddrOf(*k, *m, ohs)
                 }
-                ExprKind::Let(pat, scrutinee, span, is_recovered) => {
+                ExprKind::Let(pat, scrutinee, span, recovered) => {
                     hir::ExprKind::Let(self.arena.alloc(hir::LetExpr {
                         span: self.lower_span(*span),
                         pat: self.lower_pat(pat),
                         ty: None,
                         init: self.lower_expr(scrutinee),
-                        is_recovered: *is_recovered,
+                        recovered: *recovered,
                     }))
                 }
                 ExprKind::If(cond, then, else_opt) => {
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index 156e369..a154494 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -135,8 +135,8 @@
 
     fn lower_item_id_use_tree(&mut self, tree: &UseTree, vec: &mut SmallVec<[hir::ItemId; 1]>) {
         match &tree.kind {
-            UseTreeKind::Nested(nested_vec) => {
-                for &(ref nested, id) in nested_vec {
+            UseTreeKind::Nested { items, .. } => {
+                for &(ref nested, id) in items {
                     vec.push(hir::ItemId {
                         owner_id: hir::OwnerId { def_id: self.local_def_id(id) },
                     });
@@ -323,7 +323,7 @@
                 hir::ItemKind::Union(vdata, generics)
             }
             ItemKind::Impl(box Impl {
-                unsafety,
+                safety,
                 polarity,
                 defaultness,
                 constness,
@@ -388,7 +388,7 @@
                     ImplPolarity::Negative(s) => ImplPolarity::Negative(self.lower_span(*s)),
                 };
                 hir::ItemKind::Impl(self.arena.alloc(hir::Impl {
-                    unsafety: self.lower_unsafety(*unsafety),
+                    safety: self.lower_safety(*safety),
                     polarity,
                     defaultness,
                     defaultness_span,
@@ -398,14 +398,14 @@
                     items: new_impl_items,
                 }))
             }
-            ItemKind::Trait(box Trait { is_auto, unsafety, generics, bounds, items }) => {
+            ItemKind::Trait(box Trait { is_auto, safety, generics, bounds, items }) => {
                 // FIXME(const_trait_impl, effects, fee1-dead) this should be simplified if possible
                 let constness = attrs
                     .unwrap_or(&[])
                     .iter()
                     .find(|x| x.has_name(sym::const_trait))
                     .map_or(Const::No, |x| Const::Yes(x.span));
-                let (generics, (unsafety, items, bounds)) = self.lower_generics(
+                let (generics, (safety, items, bounds)) = self.lower_generics(
                     generics,
                     constness,
                     id,
@@ -418,11 +418,11 @@
                         let items = this.arena.alloc_from_iter(
                             items.iter().map(|item| this.lower_trait_item_ref(item)),
                         );
-                        let unsafety = this.lower_unsafety(*unsafety);
-                        (unsafety, items, bounds)
+                        let safety = this.lower_safety(*safety);
+                        (safety, items, bounds)
                     },
                 );
-                hir::ItemKind::Trait(*is_auto, unsafety, generics, bounds, items)
+                hir::ItemKind::Trait(*is_auto, safety, generics, bounds, items)
             }
             ItemKind::TraitAlias(generics, bounds) => {
                 let (generics, bounds) = self.lower_generics(
@@ -460,8 +460,8 @@
                     delegation_results.body_id,
                 )
             }
-            ItemKind::MacCall(..) => {
-                panic!("`TyMac` should have been expanded by now")
+            ItemKind::MacCall(..) | ItemKind::DelegationMac(..) => {
+                panic!("macros should have been expanded by now")
             }
         }
     }
@@ -518,7 +518,7 @@
                 let path = self.lower_use_path(res, &path, ParamMode::Explicit);
                 hir::ItemKind::Use(path, hir::UseKind::Glob)
             }
-            UseTreeKind::Nested(ref trees) => {
+            UseTreeKind::Nested { items: ref trees, .. } => {
                 // Nested imports are desugared into simple imports.
                 // So, if we start with
                 //
@@ -845,7 +845,9 @@
                 );
                 (delegation_results.generics, item_kind, true)
             }
-            AssocItemKind::MacCall(..) => panic!("macro item shouldn't exist at this point"),
+            AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
+                panic!("macros should have been expanded by now")
+            }
         };
 
         let item = hir::TraitItem {
@@ -869,7 +871,9 @@
             AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
                 has_self: self.delegation_has_self(i.id, delegation.id, i.span),
             },
-            AssocItemKind::MacCall(..) => unimplemented!(),
+            AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
+                panic!("macros should have been expanded by now")
+            }
         };
         let id = hir::TraitItemId { owner_id: hir::OwnerId { def_id: self.local_def_id(i.id) } };
         hir::TraitItemRef {
@@ -964,7 +968,9 @@
                     hir::ImplItemKind::Fn(delegation_results.sig, delegation_results.body_id),
                 )
             }
-            AssocItemKind::MacCall(..) => panic!("`TyMac` should have been expanded by now"),
+            AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
+                panic!("macros should have been expanded by now")
+            }
         };
 
         let item = hir::ImplItem {
@@ -993,7 +999,9 @@
                 AssocItemKind::Delegation(box delegation) => hir::AssocItemKind::Fn {
                     has_self: self.delegation_has_self(i.id, delegation.id, i.span),
                 },
-                AssocItemKind::MacCall(..) => unimplemented!(),
+                AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
+                    panic!("macros should have been expanded by now")
+                }
             },
             trait_item_def_id: self
                 .resolver
@@ -1352,7 +1360,7 @@
             hir::IsAsync::NotAsync
         };
         hir::FnHeader {
-            unsafety: self.lower_unsafety(h.unsafety),
+            safety: self.lower_safety(h.safety),
             asyncness: asyncness,
             constness: self.lower_constness(h.constness),
             abi: self.lower_extern(h.ext),
@@ -1402,10 +1410,10 @@
         }
     }
 
-    pub(super) fn lower_unsafety(&mut self, u: Unsafe) -> hir::Unsafety {
-        match u {
-            Unsafe::Yes(_) => hir::Unsafety::Unsafe,
-            Unsafe::No => hir::Unsafety::Normal,
+    pub(super) fn lower_safety(&mut self, s: Safety) -> hir::Safety {
+        match s {
+            Safety::Unsafe(_) => hir::Safety::Unsafe,
+            Safety::Default => hir::Safety::Safe,
         }
     }
 
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index 6c54363..a9af5ad 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -1283,7 +1283,8 @@
                         fields.iter().enumerate().map(|f| this.lower_field_def(f)),
                     );
                     let span = t.span;
-                    let variant_data = hir::VariantData::Struct { fields, recovered: false };
+                    let variant_data =
+                        hir::VariantData::Struct { fields, recovered: ast::Recovered::No };
                     // FIXME: capture the generics from the outer adt.
                     let generics = hir::Generics::empty();
                     let kind = match t.kind {
@@ -1323,7 +1324,7 @@
                 let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
                 hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy {
                     generic_params,
-                    unsafety: self.lower_unsafety(f.unsafety),
+                    safety: self.lower_safety(f.safety),
                     abi: self.lower_extern(f.ext),
                     decl: self.lower_fn_decl(&f.decl, t.id, t.span, FnDeclKind::Pointer, None),
                     param_names: self.lower_fn_params_to_names(&f.decl),
@@ -1406,7 +1407,7 @@
                         bounds,
                         fn_kind,
                         itctx,
-                        precise_capturing.as_deref().map(|(args, _)| args.as_slice()),
+                        precise_capturing.as_deref().map(|(args, span)| (args.as_slice(), *span)),
                     ),
                     ImplTraitContext::Universal => {
                         if let Some(&(_, span)) = precise_capturing.as_deref() {
@@ -1522,7 +1523,7 @@
         bounds: &GenericBounds,
         fn_kind: Option<FnDeclKind>,
         itctx: ImplTraitContext,
-        precise_capturing_args: Option<&[PreciseCapturingArg]>,
+        precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>,
     ) -> hir::TyKind<'hir> {
         // Make sure we know that some funky desugaring has been going on here.
         // This is a first: there is code in other places like for loop
@@ -1532,7 +1533,7 @@
         let opaque_ty_span = self.mark_span_with_reason(DesugaringKind::OpaqueTy, span, None);
 
         let captured_lifetimes_to_duplicate =
-            if let Some(precise_capturing) = precise_capturing_args {
+            if let Some((precise_capturing, _)) = precise_capturing_args {
                 // We'll actually validate these later on; all we need is the list of
                 // lifetimes to duplicate during this portion of lowering.
                 precise_capturing
@@ -1606,7 +1607,7 @@
         captured_lifetimes_to_duplicate: FxIndexSet<Lifetime>,
         span: Span,
         opaque_ty_span: Span,
-        precise_capturing_args: Option<&[PreciseCapturingArg]>,
+        precise_capturing_args: Option<(&[PreciseCapturingArg], Span)>,
         lower_item_bounds: impl FnOnce(&mut Self) -> &'hir [hir::GenericBound<'hir>],
     ) -> hir::TyKind<'hir> {
         let opaque_ty_def_id = self.create_def(
@@ -1697,8 +1698,11 @@
                 this.with_remapping(captured_to_synthesized_mapping, |this| {
                     (
                         lower_item_bounds(this),
-                        precise_capturing_args.map(|precise_capturing| {
-                            this.lower_precise_capturing_args(precise_capturing)
+                        precise_capturing_args.map(|(precise_capturing, span)| {
+                            (
+                                this.lower_precise_capturing_args(precise_capturing),
+                                this.lower_span(span),
+                            )
                         }),
                     )
                 });
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index a3731e9..31a184f 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -55,9 +55,6 @@
 ast_passes_constraint_on_negative_bound =
     associated type constraints not allowed on negative bounds
 
-ast_passes_deprecated_where_clause_location =
-    where clause not allowed here
-
 ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
     .label = not supported
     .suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
@@ -80,8 +77,6 @@
     .suggestion = remove the {$remove_descr}
     .label = `extern` block begins here
 
-ast_passes_extern_without_abi = extern declarations without an explicit ABI are deprecated
-
 ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
     .suggestion = remove the attribute
     .stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 172e97e..c57be3c 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -27,7 +27,6 @@
 use thin_vec::thin_vec;
 
 use crate::errors;
-use crate::fluent_generated as fluent;
 
 /// Is `self` allowed semantically as the first parameter in an `FnDecl`?
 enum SelfSemantic {
@@ -521,7 +520,7 @@
     fn check_foreign_fn_headerless(
         &self,
         // Deconstruct to ensure exhaustiveness
-        FnHeader { unsafety, coroutine_kind, constness, ext }: FnHeader,
+        FnHeader { safety, coroutine_kind, constness, ext }: FnHeader,
     ) {
         let report_err = |span| {
             self.dcx().emit_err(errors::FnQualifierInExtern {
@@ -529,9 +528,9 @@
                 block: self.current_extern_span(),
             });
         };
-        match unsafety {
-            Unsafe::Yes(span) => report_err(span),
-            Unsafe::No => (),
+        match safety {
+            Safety::Unsafe(span) => report_err(span),
+            Safety::Default => (),
         }
         match coroutine_kind {
             Some(knd) => report_err(knd.span()),
@@ -592,7 +591,7 @@
             (Some(FnCtxt::Free), Some(header)) => match header.ext {
                 Extern::Explicit(StrLit { symbol_unescaped: sym::C, .. }, _)
                 | Extern::Implicit(_)
-                    if matches!(header.unsafety, Unsafe::Yes(_)) =>
+                    if matches!(header.safety, Safety::Unsafe(_)) =>
                 {
                     return;
                 }
@@ -766,11 +765,10 @@
             .span_to_snippet(span)
             .is_ok_and(|snippet| !snippet.starts_with("#["))
         {
-            self.lint_buffer.buffer_lint_with_diagnostic(
+            self.lint_buffer.buffer_lint(
                 MISSING_ABI,
                 id,
                 span,
-                fluent::ast_passes_extern_without_abi,
                 BuiltinLintDiag::MissingAbi(span, abi::Abi::FALLBACK),
             )
         }
@@ -891,7 +889,7 @@
 
         match &item.kind {
             ItemKind::Impl(box Impl {
-                unsafety,
+                safety,
                 polarity,
                 defaultness: _,
                 constness,
@@ -910,7 +908,7 @@
                         // which isn't allowed. Not a problem for this obscure, obsolete syntax.
                         this.dcx().emit_fatal(errors::ObsoleteAuto { span: item.span });
                     }
-                    if let (&Unsafe::Yes(span), &ImplPolarity::Negative(sp)) = (unsafety, polarity)
+                    if let (&Safety::Unsafe(span), &ImplPolarity::Negative(sp)) = (safety, polarity)
                     {
                         this.dcx().emit_err(errors::UnsafeNegativeImpl {
                             span: sp.to(t.path.span),
@@ -933,7 +931,7 @@
                 return; // Avoid visiting again.
             }
             ItemKind::Impl(box Impl {
-                unsafety,
+                safety,
                 polarity,
                 defaultness,
                 constness,
@@ -956,7 +954,7 @@
                         &item.vis,
                         errors::VisibilityNotPermittedNote::IndividualImplItems,
                     );
-                    if let &Unsafe::Yes(span) = unsafety {
+                    if let &Safety::Unsafe(span) = safety {
                         this.dcx().emit_err(errors::InherentImplCannotUnsafe {
                             span: self_ty.span,
                             annotation_span: span,
@@ -1020,13 +1018,13 @@
                 walk_list!(self, visit_attribute, &item.attrs);
                 return; // Avoid visiting again.
             }
-            ItemKind::ForeignMod(ForeignMod { abi, unsafety, .. }) => {
+            ItemKind::ForeignMod(ForeignMod { abi, safety, .. }) => {
                 let old_item = mem::replace(&mut self.extern_mod, Some(item));
                 self.visibility_not_permitted(
                     &item.vis,
                     errors::VisibilityNotPermittedNote::IndividualForeignItems,
                 );
-                if let &Unsafe::Yes(span) = unsafety {
+                if let &Safety::Unsafe(span) = safety {
                     self.dcx().emit_err(errors::UnsafeItem { span, kind: "extern block" });
                 }
                 if abi.is_none() {
@@ -1078,8 +1076,8 @@
                 walk_list!(self, visit_attribute, &item.attrs);
                 return; // Avoid visiting again
             }
-            ItemKind::Mod(unsafety, mod_kind) => {
-                if let &Unsafe::Yes(span) = unsafety {
+            ItemKind::Mod(safety, mod_kind) => {
+                if let &Safety::Unsafe(span) = safety {
                     self.dcx().emit_err(errors::UnsafeItem { span, kind: "module" });
                 }
                 // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584).
@@ -1428,17 +1426,15 @@
             Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
                 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
                     if let Some(ident) = ident {
-                        let msg = match ctxt {
-                            FnCtxt::Foreign => fluent::ast_passes_pattern_in_foreign,
-                            _ => fluent::ast_passes_pattern_in_bodiless,
-                        };
-                        let diag = BuiltinLintDiag::PatternsInFnsWithoutBody(span, ident);
-                        self.lint_buffer.buffer_lint_with_diagnostic(
+                        self.lint_buffer.buffer_lint(
                             PATTERNS_IN_FNS_WITHOUT_BODY,
                             id,
                             span,
-                            msg,
-                            diag,
+                            BuiltinLintDiag::PatternsInFnsWithoutBody {
+                                span,
+                                ident,
+                                is_foreign: matches!(ctxt, FnCtxt::Foreign),
+                            },
                         )
                     }
                 } else {
@@ -1510,12 +1506,11 @@
                     Some((right, snippet))
                 }
             };
-            self.lint_buffer.buffer_lint_with_diagnostic(
+            self.lint_buffer.buffer_lint(
                 DEPRECATED_WHERE_CLAUSE_LOCATION,
                 item.id,
                 err.span,
-                fluent::ast_passes_deprecated_where_clause_location,
-                BuiltinLintDiag::DeprecatedWhereclauseLocation(sugg),
+                BuiltinLintDiag::DeprecatedWhereclauseLocation(err.span, sugg),
             );
         }
 
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 25a125f..a95a7bd 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -669,6 +669,7 @@
 
 #[derive(Diagnostic)]
 #[diag(ast_passes_pattern_in_foreign, code = E0130)]
+// FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`)
 pub struct PatternInForeign {
     #[primary_span]
     #[label]
@@ -677,6 +678,7 @@
 
 #[derive(Diagnostic)]
 #[diag(ast_passes_pattern_in_bodiless, code = E0642)]
+// FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::PatternsInFnsWithoutBody`)
 pub struct PatternInBodiless {
     #[primary_span]
     #[label]
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 6622caa..a522f04 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -560,6 +560,7 @@
     gate_all!(postfix_match, "postfix match is experimental");
     gate_all!(mut_ref, "mutable by-reference bindings are experimental");
     gate_all!(precise_capturing, "precise captures on `impl Trait` are experimental");
+    gate_all!(global_registration, "global registration is experimental");
 
     if !visitor.features.never_patterns {
         if let Some(spans) = spans.get(&sym::never_patterns) {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 2c17682..545b98a 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -55,8 +55,8 @@
 
 pub struct Comments<'a> {
     sm: &'a SourceMap,
-    comments: Vec<Comment>,
-    current: usize,
+    // Stored in reverse order so we can consume them by popping.
+    reversed_comments: Vec<Comment>,
 }
 
 /// Returns `None` if the first `col` chars of `s` contain a non-whitespace char.
@@ -182,21 +182,25 @@
 
 impl<'a> Comments<'a> {
     pub fn new(sm: &'a SourceMap, filename: FileName, input: String) -> Comments<'a> {
-        let comments = gather_comments(sm, filename, input);
-        Comments { sm, comments, current: 0 }
+        let mut comments = gather_comments(sm, filename, input);
+        comments.reverse();
+        Comments { sm, reversed_comments: comments }
     }
 
-    // FIXME: This shouldn't probably clone lmao
-    fn next(&self) -> Option<Comment> {
-        self.comments.get(self.current).cloned()
+    fn peek(&self) -> Option<&Comment> {
+        self.reversed_comments.last()
+    }
+
+    fn next(&mut self) -> Option<Comment> {
+        self.reversed_comments.pop()
     }
 
     fn trailing_comment(
-        &self,
+        &mut self,
         span: rustc_span::Span,
         next_pos: Option<BytePos>,
     ) -> Option<Comment> {
-        if let Some(cmnt) = self.next() {
+        if let Some(cmnt) = self.peek() {
             if cmnt.style != CommentStyle::Trailing {
                 return None;
             }
@@ -204,7 +208,7 @@
             let comment_line = self.sm.lookup_char_pos(cmnt.pos);
             let next = next_pos.unwrap_or_else(|| cmnt.pos + BytePos(1));
             if span.hi() < cmnt.pos && cmnt.pos < next && span_line.line == comment_line.line {
-                return Some(cmnt);
+                return Some(self.next().unwrap());
             }
         }
 
@@ -400,7 +404,8 @@
 
 /// This trait is used for both AST and HIR pretty-printing.
 pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::DerefMut {
-    fn comments(&mut self) -> &mut Option<Comments<'a>>;
+    fn comments(&self) -> Option<&Comments<'a>>;
+    fn comments_mut(&mut self) -> Option<&mut Comments<'a>>;
     fn ann_post(&mut self, ident: Ident);
     fn print_generic_args(&mut self, args: &ast::GenericArgs, colons_before_params: bool);
 
@@ -442,18 +447,18 @@
 
     fn maybe_print_comment(&mut self, pos: BytePos) -> bool {
         let mut has_comment = false;
-        while let Some(cmnt) = self.next_comment() {
-            if cmnt.pos < pos {
-                has_comment = true;
-                self.print_comment(&cmnt);
-            } else {
+        while let Some(cmnt) = self.peek_comment() {
+            if cmnt.pos >= pos {
                 break;
             }
+            has_comment = true;
+            let cmnt = self.next_comment().unwrap();
+            self.print_comment(cmnt);
         }
         has_comment
     }
 
-    fn print_comment(&mut self, cmnt: &Comment) {
+    fn print_comment(&mut self, cmnt: Comment) {
         match cmnt.style {
             CommentStyle::Mixed => {
                 if !self.is_beginning_of_line() {
@@ -517,19 +522,23 @@
                 self.hardbreak();
             }
         }
-        if let Some(cmnts) = self.comments() {
-            cmnts.current += 1;
-        }
+    }
+
+    fn peek_comment<'b>(&'b self) -> Option<&'b Comment>
+    where
+        'a: 'b,
+    {
+        self.comments().and_then(|c| c.peek())
     }
 
     fn next_comment(&mut self) -> Option<Comment> {
-        self.comments().as_mut().and_then(|c| c.next())
+        self.comments_mut().and_then(|c| c.next())
     }
 
     fn maybe_print_trailing_comment(&mut self, span: rustc_span::Span, next_pos: Option<BytePos>) {
-        if let Some(cmnts) = self.comments() {
+        if let Some(cmnts) = self.comments_mut() {
             if let Some(cmnt) = cmnts.trailing_comment(span, next_pos) {
-                self.print_comment(&cmnt);
+                self.print_comment(cmnt);
             }
         }
     }
@@ -537,11 +546,11 @@
     fn print_remaining_comments(&mut self) {
         // If there aren't any remaining comments, then we need to manually
         // make sure there is a line break at the end.
-        if self.next_comment().is_none() {
+        if self.peek_comment().is_none() {
             self.hardbreak();
         }
         while let Some(cmnt) = self.next_comment() {
-            self.print_comment(&cmnt)
+            self.print_comment(cmnt)
         }
     }
 
@@ -852,8 +861,6 @@
             token::NtBlock(e) => self.block_to_string(e),
             token::NtStmt(e) => self.stmt_to_string(e),
             token::NtPat(e) => self.pat_to_string(e),
-            &token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(e, is_raw.into()).to_string(),
-            token::NtLifetime(e) => e.to_string(),
             token::NtLiteral(e) => self.expr_to_string(e),
             token::NtVis(e) => self.vis_to_string(e),
         }
@@ -915,10 +922,14 @@
             token::Literal(lit) => literal_to_string(lit).into(),
 
             /* Name components */
-            token::Ident(s, is_raw) => {
-                IdentPrinter::new(s, is_raw.into(), convert_dollar_crate).to_string().into()
+            token::Ident(name, is_raw) => {
+                IdentPrinter::new(name, is_raw.into(), convert_dollar_crate).to_string().into()
             }
-            token::Lifetime(s) => s.to_string().into(),
+            token::NtIdent(ident, is_raw) => {
+                IdentPrinter::for_ast_ident(ident, is_raw.into()).to_string().into()
+            }
+            token::Lifetime(name) => name.to_string().into(),
+            token::NtLifetime(ident) => ident.name.to_string().into(),
 
             /* Other */
             token::DocComment(comment_kind, attr_style, data) => {
@@ -926,7 +937,7 @@
             }
             token::Eof => "<eof>".into(),
 
-            token::Interpolated(ref nt) => self.nonterminal_to_string(&nt.0).into(),
+            token::Interpolated(ref nt) => self.nonterminal_to_string(&nt).into(),
         }
     }
 
@@ -994,8 +1005,12 @@
 }
 
 impl<'a> PrintState<'a> for State<'a> {
-    fn comments(&mut self) -> &mut Option<Comments<'a>> {
-        &mut self.comments
+    fn comments(&self) -> Option<&Comments<'a>> {
+        self.comments.as_ref()
+    }
+
+    fn comments_mut(&mut self) -> Option<&mut Comments<'a>> {
+        self.comments.as_mut()
     }
 
     fn ann_post(&mut self, ident: Ident) {
@@ -1138,7 +1153,7 @@
                 self.pclose();
             }
             ast::TyKind::BareFn(f) => {
-                self.print_ty_fn(f.ext, f.unsafety, &f.decl, None, &f.generic_params);
+                self.print_ty_fn(f.ext, f.safety, &f.decl, None, &f.generic_params);
             }
             ast::TyKind::Path(None, path) => {
                 self.print_path(path, false, 0);
@@ -1238,7 +1253,11 @@
                 if let Some((init, els)) = loc.kind.init_else_opt() {
                     self.nbsp();
                     self.word_space("=");
-                    self.print_expr(init, FixupContext::default());
+                    self.print_expr_cond_paren(
+                        init,
+                        els.is_some() && classify::expr_trailing_brace(init).is_some(),
+                        FixupContext::default(),
+                    );
                     if let Some(els) = els {
                         self.cbox(INDENT_UNIT);
                         self.ibox(INDENT_UNIT);
@@ -1892,7 +1911,7 @@
     fn print_ty_fn(
         &mut self,
         ext: ast::Extern,
-        unsafety: ast::Unsafe,
+        safety: ast::Safety,
         decl: &ast::FnDecl,
         name: Option<Ident>,
         generic_params: &[ast::GenericParam],
@@ -1908,7 +1927,7 @@
             },
             span: DUMMY_SP,
         };
-        let header = ast::FnHeader { unsafety, ext, ..ast::FnHeader::default() };
+        let header = ast::FnHeader { safety, ext, ..ast::FnHeader::default() };
         self.print_fn(decl, header, name, &generics);
         self.end();
     }
@@ -1916,7 +1935,7 @@
     fn print_fn_header_info(&mut self, header: ast::FnHeader) {
         self.print_constness(header.constness);
         header.coroutine_kind.map(|coroutine_kind| self.print_coroutine_kind(coroutine_kind));
-        self.print_unsafety(header.unsafety);
+        self.print_safety(header.safety);
 
         match header.ext {
             ast::Extern::None => {}
@@ -1933,10 +1952,10 @@
         self.word("fn")
     }
 
-    fn print_unsafety(&mut self, s: ast::Unsafe) {
+    fn print_safety(&mut self, s: ast::Safety) {
         match s {
-            ast::Unsafe::No => {}
-            ast::Unsafe::Yes(_) => self.word_nbsp("unsafe"),
+            ast::Safety::Default => {}
+            ast::Safety::Unsafe(_) => self.word_nbsp("unsafe"),
         }
     }
 
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 93400c6..1e117c4 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -780,7 +780,7 @@
                 }
                 _ => {
                     self.end(); // Close the ibox for the pattern.
-                    self.print_expr(body, FixupContext::new_stmt());
+                    self.print_expr(body, FixupContext::new_match_arm());
                     self.word(",");
                 }
             }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs
index d21cb82..86d4796 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/fixup.rs
@@ -49,6 +49,38 @@
     ///     No parentheses required.
     leftmost_subexpression_in_stmt: bool,
 
+    /// Print expression such that it can be parsed as a match arm.
+    ///
+    /// This is almost equivalent to `stmt`, but the grammar diverges a tiny bit
+    /// between statements and match arms when it comes to braced macro calls.
+    /// Macro calls with brace delimiter terminate a statement without a
+    /// semicolon, but do not terminate a match-arm without comma.
+    ///
+    /// ```ignore (illustrative)
+    /// m! {} - 1;  // two statements: a macro call followed by -1 literal
+    ///
+    /// match () {
+    ///     _ => m! {} - 1,  // binary subtraction operator
+    /// }
+    /// ```
+    match_arm: bool,
+
+    /// This is almost equivalent to `leftmost_subexpression_in_stmt`, other
+    /// than for braced macro calls.
+    ///
+    /// If we have `m! {} - 1` as an expression, the leftmost subexpression
+    /// `m! {}` will need to be parenthesized in the statement case but not the
+    /// match-arm case.
+    ///
+    /// ```ignore (illustrative)
+    /// (m! {}) - 1;  // subexpression needs parens
+    ///
+    /// match () {
+    ///     _ => m! {} - 1,  // no parens
+    /// }
+    /// ```
+    leftmost_subexpression_in_match_arm: bool,
+
     /// This is the difference between:
     ///
     /// ```ignore (illustrative)
@@ -68,6 +100,8 @@
         FixupContext {
             stmt: false,
             leftmost_subexpression_in_stmt: false,
+            match_arm: false,
+            leftmost_subexpression_in_match_arm: false,
             parenthesize_exterior_struct_lit: false,
         }
     }
@@ -76,13 +110,16 @@
 impl FixupContext {
     /// Create the initial fixup for printing an expression in statement
     /// position.
-    ///
-    /// This is currently also used for printing an expression as a match-arm,
-    /// but this is incorrect and leads to over-parenthesizing.
     pub fn new_stmt() -> Self {
         FixupContext { stmt: true, ..FixupContext::default() }
     }
 
+    /// Create the initial fixup for printing an expression as the right-hand
+    /// side of a match arm.
+    pub fn new_match_arm() -> Self {
+        FixupContext { match_arm: true, ..FixupContext::default() }
+    }
+
     /// Create the initial fixup for printing an expression as the "condition"
     /// of an `if` or `while`. There are a few other positions which are
     /// grammatically equivalent and also use this, such as the iterator
@@ -106,6 +143,9 @@
         FixupContext {
             stmt: false,
             leftmost_subexpression_in_stmt: self.stmt || self.leftmost_subexpression_in_stmt,
+            match_arm: false,
+            leftmost_subexpression_in_match_arm: self.match_arm
+                || self.leftmost_subexpression_in_match_arm,
             ..self
         }
     }
@@ -119,7 +159,13 @@
     /// example the `$b` in `$a + $b` and `-$b`, but not the one in `[$b]` or
     /// `$a.f($b)`.
     pub fn subsequent_subexpression(self) -> Self {
-        FixupContext { stmt: false, leftmost_subexpression_in_stmt: false, ..self }
+        FixupContext {
+            stmt: false,
+            leftmost_subexpression_in_stmt: false,
+            match_arm: false,
+            leftmost_subexpression_in_match_arm: false,
+            ..self
+        }
     }
 
     /// Determine whether parentheses are needed around the given expression to
@@ -128,7 +174,8 @@
     /// The documentation on `FixupContext::leftmost_subexpression_in_stmt` has
     /// examples.
     pub fn would_cause_statement_boundary(self, expr: &Expr) -> bool {
-        self.leftmost_subexpression_in_stmt && !classify::expr_requires_semi_to_be_stmt(expr)
+        (self.leftmost_subexpression_in_stmt && !classify::expr_requires_semi_to_be_stmt(expr))
+            || (self.leftmost_subexpression_in_match_arm && classify::expr_is_complete(expr))
     }
 
     /// Determine whether parentheses are needed around the given `let`
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 61398f7..59d9b0c 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -5,6 +5,7 @@
 use ast::StaticItem;
 use itertools::{Itertools, Position};
 use rustc_ast as ast;
+use rustc_ast::ptr::P;
 use rustc_ast::ModKind;
 use rustc_span::symbol::Ident;
 
@@ -197,10 +198,10 @@
                     &item.attrs,
                 );
             }
-            ast::ItemKind::Mod(unsafety, mod_kind) => {
+            ast::ItemKind::Mod(safety, mod_kind) => {
                 self.head(Self::to_string(|s| {
                     s.print_visibility(&item.vis);
-                    s.print_unsafety(*unsafety);
+                    s.print_safety(*safety);
                     s.word("mod");
                 }));
                 self.print_ident(item.ident);
@@ -225,7 +226,7 @@
             }
             ast::ItemKind::ForeignMod(nmod) => {
                 self.head(Self::to_string(|s| {
-                    s.print_unsafety(nmod.unsafety);
+                    s.print_safety(nmod.safety);
                     s.word("extern");
                 }));
                 if let Some(abi) = nmod.abi {
@@ -274,7 +275,7 @@
                 self.print_struct(struct_def, generics, item.ident, item.span, true);
             }
             ast::ItemKind::Impl(box ast::Impl {
-                unsafety,
+                safety,
                 polarity,
                 defaultness,
                 constness,
@@ -286,7 +287,7 @@
                 self.head("");
                 self.print_visibility(&item.vis);
                 self.print_defaultness(*defaultness);
-                self.print_unsafety(*unsafety);
+                self.print_safety(*safety);
                 self.word("impl");
 
                 if generics.params.is_empty() {
@@ -322,7 +323,7 @@
             }
             ast::ItemKind::Trait(box ast::Trait {
                 is_auto,
-                unsafety,
+                safety,
                 generics,
                 bounds,
                 items,
@@ -330,7 +331,7 @@
             }) => {
                 self.head("");
                 self.print_visibility(&item.vis);
-                self.print_unsafety(*unsafety);
+                self.print_safety(*safety);
                 self.print_is_auto(*is_auto);
                 self.word_nbsp("trait");
                 self.print_ident(item.ident);
@@ -374,9 +375,22 @@
                     state.print_visibility(&item.vis)
                 });
             }
-            ast::ItemKind::Delegation(box delegation) => {
-                self.print_delegation(delegation, &item.vis, &item.attrs)
-            }
+            ast::ItemKind::Delegation(deleg) => self.print_delegation(
+                &item.attrs,
+                &item.vis,
+                &deleg.qself,
+                &deleg.path,
+                None,
+                &deleg.body,
+            ),
+            ast::ItemKind::DelegationMac(deleg) => self.print_delegation(
+                &item.attrs,
+                &item.vis,
+                &deleg.qself,
+                &deleg.prefix,
+                Some(&deleg.suffixes),
+                &deleg.body,
+            ),
         }
         self.ann.post(self, AnnNode::Item(item))
     }
@@ -553,31 +567,63 @@
                     self.word(";");
                 }
             }
-            ast::AssocItemKind::Delegation(box delegation) => {
-                self.print_delegation(delegation, vis, &item.attrs)
-            }
+            ast::AssocItemKind::Delegation(deleg) => self.print_delegation(
+                &item.attrs,
+                vis,
+                &deleg.qself,
+                &deleg.path,
+                None,
+                &deleg.body,
+            ),
+            ast::AssocItemKind::DelegationMac(deleg) => self.print_delegation(
+                &item.attrs,
+                vis,
+                &deleg.qself,
+                &deleg.prefix,
+                Some(&deleg.suffixes),
+                &deleg.body,
+            ),
         }
         self.ann.post(self, AnnNode::SubItem(id))
     }
 
     pub(crate) fn print_delegation(
         &mut self,
-        delegation: &ast::Delegation,
-        vis: &ast::Visibility,
         attrs: &[ast::Attribute],
+        vis: &ast::Visibility,
+        qself: &Option<P<ast::QSelf>>,
+        path: &ast::Path,
+        suffixes: Option<&[(Ident, Option<Ident>)]>,
+        body: &Option<P<ast::Block>>,
     ) {
-        if delegation.body.is_some() {
+        if body.is_some() {
             self.head("");
         }
         self.print_visibility(vis);
-        self.word_space("reuse");
+        self.word_nbsp("reuse");
 
-        if let Some(qself) = &delegation.qself {
-            self.print_qpath(&delegation.path, qself, false);
+        if let Some(qself) = qself {
+            self.print_qpath(path, qself, false);
         } else {
-            self.print_path(&delegation.path, false, 0);
+            self.print_path(path, false, 0);
         }
-        if let Some(body) = &delegation.body {
+        if let Some(suffixes) = suffixes {
+            self.word("::");
+            self.word("{");
+            for (i, (ident, rename)) in suffixes.iter().enumerate() {
+                self.print_ident(*ident);
+                if let Some(rename) = rename {
+                    self.nbsp();
+                    self.word_nbsp("as");
+                    self.print_ident(*rename);
+                }
+                if i != suffixes.len() - 1 {
+                    self.word_space(",");
+                }
+            }
+            self.word("}");
+        }
+        if let Some(body) = body {
             self.nbsp();
             self.print_block_with_attrs(body, attrs);
         } else {
@@ -715,7 +761,7 @@
                 }
                 self.word("*");
             }
-            ast::UseTreeKind::Nested(items) => {
+            ast::UseTreeKind::Nested { items, .. } => {
                 if !tree.prefix.segments.is_empty() {
                     self.print_path(&tree.prefix, false, 0);
                     self.word("::");
@@ -734,7 +780,7 @@
                         self.print_use_tree(&use_tree.0);
                         if !is_last {
                             self.word(",");
-                            if let ast::UseTreeKind::Nested(_) = use_tree.0.kind {
+                            if let ast::UseTreeKind::Nested { .. } = use_tree.0.kind {
                                 self.hardbreak();
                             } else {
                                 self.space();
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index c08bf28..5113c5a 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -528,15 +528,10 @@
         try_gate_cfg(cfg.name, cfg.span, sess, features);
         match sess.psess.check_config.expecteds.get(&cfg.name) {
             Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
-                sess.psess.buffer_lint_with_diagnostic(
+                sess.psess.buffer_lint(
                     UNEXPECTED_CFGS,
                     cfg.span,
                     lint_node_id,
-                    if let Some(value) = cfg.value {
-                        format!("unexpected `cfg` condition value: `{value}`")
-                    } else {
-                        format!("unexpected `cfg` condition value: (none)")
-                    },
                     BuiltinLintDiag::UnexpectedCfgValue(
                         (cfg.name, cfg.name_span),
                         cfg.value.map(|v| (v, cfg.value_span.unwrap())),
@@ -544,11 +539,10 @@
                 );
             }
             None if sess.psess.check_config.exhaustive_names => {
-                sess.psess.buffer_lint_with_diagnostic(
+                sess.psess.buffer_lint(
                     UNEXPECTED_CFGS,
                     cfg.span,
                     lint_node_id,
-                    format!("unexpected `cfg` condition name: `{}`", cfg.name),
                     BuiltinLintDiag::UnexpectedCfgName(
                         (cfg.name, cfg.name_span),
                         cfg.value.map(|v| (v, cfg.value_span.unwrap())),
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 6c82dd1..2f1b2ce 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -22,9 +22,10 @@
     Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
     TerminatorKind, VarBindingForm,
 };
+use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{
-    self, suggest_constraining_type_params, PredicateKind, ToPredicate, Ty, TyCtxt,
-    TypeSuperVisitable, TypeVisitor,
+    self, suggest_constraining_type_params, PredicateKind, Ty, TyCtxt, TypeSuperVisitable,
+    TypeVisitor, Upcast,
 };
 use rustc_middle::util::CallKind;
 use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
@@ -494,7 +495,7 @@
                 {
                     self.suggest_cloning(err, ty, expr, None, Some(move_spans));
                 } else if self.suggest_hoisting_call_outside_loop(err, expr) {
-                    // The place where the the type moves would be misleading to suggest clone.
+                    // The place where the type moves would be misleading to suggest clone.
                     // #121466
                     self.suggest_cloning(err, ty, expr, None, Some(move_spans));
                 }
@@ -651,7 +652,7 @@
                     }
 
                     // FIXME: We make sure that this is a normal top-level binding,
-                    // but we could suggest `todo!()` for all uninitialized bindings in the pattern pattern
+                    // but we could suggest `todo!()` for all uninitialized bindings in the pattern
                     if let hir::StmtKind::Let(hir::LetStmt { span, ty, init: None, pat, .. }) =
                         &ex.kind
                         && let hir::PatKind::Binding(..) = pat.kind
@@ -1914,7 +1915,7 @@
             self.infcx.err_ctxt().suggest_derive(
                 &obligation,
                 err,
-                trait_ref.to_predicate(self.infcx.tcx),
+                trait_ref.upcast(self.infcx.tcx),
             );
         }
     }
@@ -3342,6 +3343,10 @@
                 } else if string.starts_with("gen") {
                     // `gen` is 3 chars long
                     Some(3)
+                } else if string.starts_with("static") {
+                    // `static` is 6 chars long
+                    // This is used for `!Unpin` coroutines
+                    Some(6)
                 } else {
                     None
                 };
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 5ebdb69..e3ad92a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -317,36 +317,39 @@
             let mut has_dyn = false;
             let mut failed = false;
 
-            let elaborated_args = std::iter::zip(*args, &generics.params).map(|(arg, param)| {
-                if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) {
-                    let default = tcx.object_lifetime_default(param.def_id);
+            let elaborated_args =
+                std::iter::zip(*args, &generics.own_params).map(|(arg, param)| {
+                    if let Some(ty::Dynamic(obj, _, ty::Dyn)) = arg.as_type().map(Ty::kind) {
+                        let default = tcx.object_lifetime_default(param.def_id);
 
-                    let re_static = tcx.lifetimes.re_static;
+                        let re_static = tcx.lifetimes.re_static;
 
-                    let implied_region = match default {
-                        // This is not entirely precise.
-                        ObjectLifetimeDefault::Empty => re_static,
-                        ObjectLifetimeDefault::Ambiguous => {
-                            failed = true;
-                            re_static
-                        }
-                        ObjectLifetimeDefault::Param(param_def_id) => {
-                            let index = generics.param_def_id_to_index[&param_def_id] as usize;
-                            args.get(index).and_then(|arg| arg.as_region()).unwrap_or_else(|| {
+                        let implied_region = match default {
+                            // This is not entirely precise.
+                            ObjectLifetimeDefault::Empty => re_static,
+                            ObjectLifetimeDefault::Ambiguous => {
                                 failed = true;
                                 re_static
-                            })
-                        }
-                        ObjectLifetimeDefault::Static => re_static,
-                    };
+                            }
+                            ObjectLifetimeDefault::Param(param_def_id) => {
+                                let index = generics.param_def_id_to_index[&param_def_id] as usize;
+                                args.get(index).and_then(|arg| arg.as_region()).unwrap_or_else(
+                                    || {
+                                        failed = true;
+                                        re_static
+                                    },
+                                )
+                            }
+                            ObjectLifetimeDefault::Static => re_static,
+                        };
 
-                    has_dyn = true;
+                        has_dyn = true;
 
-                    Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into()
-                } else {
-                    arg
-                }
-            });
+                        Ty::new_dynamic(tcx, obj, implied_region, ty::Dyn).into()
+                    } else {
+                        arg
+                    }
+                });
             let elaborated_ty = Ty::new_adt(tcx, *def, tcx.mk_args_from_iter(elaborated_args));
 
             if has_dyn && !failed {
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 0b4018a..88172c6 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -1344,7 +1344,7 @@
                                     Applicability::MaybeIncorrect,
                                 );
                                 for error in errors {
-                                    if let FulfillmentErrorCode::SelectionError(
+                                    if let FulfillmentErrorCode::Select(
                                         SelectionError::Unimplemented,
                                     ) = error.code
                                         && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 5d74a01..79b4850 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -9,7 +9,7 @@
 use rustc_infer::traits;
 use rustc_middle::bug;
 use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem};
-use rustc_middle::ty::{self, InstanceDef, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, Upcast};
 use rustc_middle::{
     hir::place::PlaceBase,
     mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location},
@@ -992,7 +992,7 @@
             }
         }
 
-        if look_at_return && hir.get_return_block(closure_id).is_some() {
+        if look_at_return && hir.get_fn_id_for_return_block(closure_id).is_some() {
             // ...otherwise we are probably in the tail expression of the function, point at the
             // return type.
             match self.infcx.tcx.hir_node_by_def_id(hir.get_parent_item(fn_call_id).def_id) {
@@ -1255,7 +1255,7 @@
                                 self.infcx.err_ctxt().suggest_derive(
                                     &obligation,
                                     err,
-                                    trait_ref.to_predicate(self.infcx.tcx),
+                                    trait_ref.upcast(self.infcx.tcx),
                                 );
                             }
                             Some(errors) => {
@@ -1283,7 +1283,7 @@
                                 }
                                 // The type doesn't implement Clone because of unmet obligations.
                                 for error in errors {
-                                    if let traits::FulfillmentErrorCode::SelectionError(
+                                    if let traits::FulfillmentErrorCode::Select(
                                         traits::SelectionError::Unimplemented,
                                     ) = error.code
                                         && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(
@@ -1483,10 +1483,9 @@
     } else {
         // otherwise, suggest that the user annotates the binding; we provide the
         // type of the local.
-        let ty_mut = decl_ty.builtin_deref(true).unwrap();
-        assert_eq!(ty_mut.mutbl, hir::Mutability::Not);
+        let ty = decl_ty.builtin_deref(true).unwrap();
 
-        (false, span, format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty_mut.ty))
+        (false, span, format!("{}mut {}", if decl_ty.is_ref() { "&" } else { "*" }, ty))
     }
 }
 
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index d8d582b..8112fb7 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -1098,7 +1098,7 @@
                 liberated_sig.inputs().iter().copied(),
                 peeled_ty,
                 liberated_sig.c_variadic,
-                hir::Unsafety::Normal,
+                hir::Safety::Safe,
                 rustc_target::spec::abi::Abi::Rust,
             )),
         );
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index 28c5c50..46011c1 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -1010,7 +1010,8 @@
                 clauses.iter().any(|pred| {
                     match pred.kind().skip_binder() {
                         ty::ClauseKind::Trait(data) if data.self_ty() == ty => {}
-                        ty::ClauseKind::Projection(data) if data.projection_ty.self_ty() == ty => {}
+                        ty::ClauseKind::Projection(data)
+                            if data.projection_term.self_ty() == ty => {}
                         _ => return false,
                     }
                     tcx.any_free_region_meets(pred, |r| *r == ty::ReEarlyParam(region))
diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs
index e7faec7..51ea59e 100644
--- a/compiler/rustc_borrowck/src/facts.rs
+++ b/compiler/rustc_borrowck/src/facts.rs
@@ -15,8 +15,31 @@
 #[derive(Copy, Clone, Debug)]
 pub struct RustcFacts;
 
+rustc_index::newtype_index! {
+    /// A (kinda) newtype of `RegionVid` so we can implement `Atom` on it.
+    #[orderable]
+    #[debug_format = "'?{}"]
+    pub struct PoloniusRegionVid {}
+}
+
+impl polonius_engine::Atom for PoloniusRegionVid {
+    fn index(self) -> usize {
+        self.as_usize()
+    }
+}
+impl From<RegionVid> for PoloniusRegionVid {
+    fn from(value: RegionVid) -> Self {
+        Self::from_usize(value.as_usize())
+    }
+}
+impl From<PoloniusRegionVid> for RegionVid {
+    fn from(value: PoloniusRegionVid) -> Self {
+        Self::from_usize(value.as_usize())
+    }
+}
+
 impl polonius_engine::FactTypes for RustcFacts {
-    type Origin = RegionVid;
+    type Origin = PoloniusRegionVid;
     type Loan = BorrowIndex;
     type Point = LocationIndex;
     type Variable = Local;
@@ -119,7 +142,7 @@
     ) -> Result<(), Box<dyn Error>>;
 }
 
-impl FactRow for RegionVid {
+impl FactRow for PoloniusRegionVid {
     fn write(
         &self,
         out: &mut dyn Write,
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index abe57e2..1d58014 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1312,8 +1312,7 @@
                 );
             }
 
-            Rvalue::BinaryOp(_bin_op, box (operand1, operand2))
-            | Rvalue::CheckedBinaryOp(_bin_op, box (operand1, operand2)) => {
+            Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
                 self.consume_operand(location, (operand1, span), flow_state);
                 self.consume_operand(location, (operand2, span), flow_state);
             }
diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
index a1e5997..6979910 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
+++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
@@ -302,8 +302,7 @@
                 );
             }
 
-            Rvalue::BinaryOp(_bin_op, box (operand1, operand2))
-            | Rvalue::CheckedBinaryOp(_bin_op, box (operand1, operand2)) => {
+            Rvalue::BinaryOp(_bin_op, box (operand1, operand2)) => {
                 self.consume_operand(location, operand1);
                 self.consume_operand(location, operand2);
             }
diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs
index 40126d5..9984f76 100644
--- a/compiler/rustc_borrowck/src/polonius/mod.rs
+++ b/compiler/rustc_borrowck/src/polonius/mod.rs
@@ -8,7 +8,7 @@
 use rustc_mir_dataflow::move_paths::{InitKind, InitLocation, MoveData};
 
 use crate::borrow_set::BorrowSet;
-use crate::facts::AllFacts;
+use crate::facts::{AllFacts, PoloniusRegionVid};
 use crate::location::LocationTable;
 use crate::type_check::free_region_relations::UniversalRegionRelations;
 use crate::universal_regions::UniversalRegions;
@@ -137,7 +137,9 @@
     //   the `borrow_set`, their `BorrowIndex` are synthesized as the universal region index
     //   added to the existing number of loans, as if they succeeded them in the set.
     //
-    all_facts.universal_region.extend(universal_regions.universal_regions());
+    all_facts
+        .universal_region
+        .extend(universal_regions.universal_regions().map(PoloniusRegionVid::from));
     let borrow_count = borrow_set.len();
     debug!(
         "emit_universal_region_facts: polonius placeholders, num_universals={}, borrow_count={}",
@@ -148,7 +150,7 @@
     for universal_region in universal_regions.universal_regions() {
         let universal_region_idx = universal_region.index();
         let placeholder_loan_idx = borrow_count + universal_region_idx;
-        all_facts.placeholder.push((universal_region, placeholder_loan_idx.into()));
+        all_facts.placeholder.push((universal_region.into(), placeholder_loan_idx.into()));
     }
 
     // 2: the universal region relations `outlives` constraints are emitted as
@@ -160,7 +162,7 @@
                      fr1={:?}, fr2={:?}",
                 fr1, fr2
             );
-            all_facts.known_placeholder_subset.push((fr1, fr2));
+            all_facts.known_placeholder_subset.push((fr1.into(), fr2.into()));
         }
     }
 }
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 5457444..b57cf90 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -1326,14 +1326,20 @@
         })
     }
 
-    // Evaluate whether `sup_region == sub_region`.
-    fn eval_equal(&self, r1: RegionVid, r2: RegionVid) -> bool {
+    /// Evaluate whether `sup_region == sub_region`.
+    ///
+    /// Panics if called before `solve()` executes,
+    // This is `pub` because it's used by unstable external borrowck data users, see `consumers.rs`.
+    pub fn eval_equal(&self, r1: RegionVid, r2: RegionVid) -> bool {
         self.eval_outlives(r1, r2) && self.eval_outlives(r2, r1)
     }
 
-    // Evaluate whether `sup_region: sub_region`.
+    /// Evaluate whether `sup_region: sub_region`.
+    ///
+    /// Panics if called before `solve()` executes,
+    // This is `pub` because it's used by unstable external borrowck data users, see `consumers.rs`.
     #[instrument(skip(self), level = "debug", ret)]
-    fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
+    pub fn eval_outlives(&self, sup_region: RegionVid, sub_region: RegionVid) -> bool {
         debug!(
             "sup_region's value = {:?} universal={:?}",
             self.region_value_str(sup_region),
@@ -1500,7 +1506,7 @@
         subset_errors.sort();
         subset_errors.dedup();
 
-        for (longer_fr, shorter_fr) in subset_errors.into_iter() {
+        for &(longer_fr, shorter_fr) in subset_errors.into_iter() {
             debug!(
                 "check_polonius_subset_errors: subset_error longer_fr={:?},\
                  shorter_fr={:?}",
@@ -1508,14 +1514,14 @@
             );
 
             let propagated = self.try_propagate_universal_region_error(
-                *longer_fr,
-                *shorter_fr,
+                longer_fr.into(),
+                shorter_fr.into(),
                 &mut propagated_outlives_requirements,
             );
             if propagated == RegionRelationCheckResult::Error {
                 errors_buffer.push(RegionErrorKind::RegionError {
-                    longer_fr: *longer_fr,
-                    shorter_fr: *shorter_fr,
+                    longer_fr: longer_fr.into(),
+                    shorter_fr: shorter_fr.into(),
                     fr_origin: NllRegionVariableOrigin::FreeRegion,
                     is_reported: true,
                 });
@@ -2053,15 +2059,12 @@
                     // We currently do not store the `DefId` in the `ConstraintCategory`
                     // for performances reasons. The error reporting code used by NLL only
                     // uses the span, so this doesn't cause any problems at the moment.
-                    Some(ObligationCauseCode::BindingObligation(
-                        CRATE_DEF_ID.to_def_id(),
-                        predicate_span,
-                    ))
+                    Some(ObligationCauseCode::WhereClause(CRATE_DEF_ID.to_def_id(), predicate_span))
                 } else {
                     None
                 }
             })
-            .unwrap_or_else(|| ObligationCauseCode::MiscObligation);
+            .unwrap_or_else(|| ObligationCauseCode::Misc);
 
         // Classify each of the constraints along the path.
         let mut categorized_path: Vec<BlameConstraint<'tcx>> = path
@@ -2246,7 +2249,10 @@
     }
 
     /// Access to the SCC constraint graph.
-    pub(crate) fn constraint_sccs(&self) -> &Sccs<RegionVid, ConstraintSccIndex> {
+    /// This can be used to quickly under-approximate the regions which are equal to each other
+    /// and their relative orderings.
+    // This is `pub` because it's used by unstable external borrowck data users, see `consumers.rs`.
+    pub fn constraint_sccs(&self) -> &Sccs<RegionVid, ConstraintSccIndex> {
         self.constraint_sccs.as_ref()
     }
 
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 73ba5be..f601a9d 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -40,7 +40,7 @@
     /// compares lifetimes directly, so we need to map the inference variables
     /// back to concrete lifetimes: `'static`, `ReEarlyParam` or `ReLateParam`.
     ///
-    /// First we map the regions in the the generic parameters `_Return<'1>` to
+    /// First we map the regions in the generic parameters `_Return<'1>` to
     /// their `external_name` giving `_Return<'a>`. This step is a bit involved.
     /// See the [rustc-dev-guide chapter] for more info.
     ///
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index f5757bc..d382f26 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -26,9 +26,7 @@
     renumberer.visit_body(body);
 }
 
-// FIXME(@lcnr): A lot of these variants overlap and it seems like
-// this type is only used to decide which region should be used
-// as representative. This should be cleaned up.
+// The fields are used only for debugging output in `sccs_info`.
 #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
 pub(crate) enum RegionCtxt {
     Location(Location),
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index 49d3f73..2dc2568 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -4,7 +4,7 @@
 use rustc_infer::infer::canonical::Canonical;
 use rustc_middle::bug;
 use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, Upcast};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
@@ -115,7 +115,7 @@
 
     pub(super) fn prove_predicates(
         &mut self,
-        predicates: impl IntoIterator<Item: ToPredicate<'tcx> + std::fmt::Debug>,
+        predicates: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + std::fmt::Debug>,
         locations: Locations,
         category: ConstraintCategory<'tcx>,
     ) {
@@ -127,12 +127,12 @@
     #[instrument(skip(self), level = "debug")]
     pub(super) fn prove_predicate(
         &mut self,
-        predicate: impl ToPredicate<'tcx> + std::fmt::Debug,
+        predicate: impl Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + std::fmt::Debug,
         locations: Locations,
         category: ConstraintCategory<'tcx>,
     ) {
         let param_env = self.param_env;
-        let predicate = predicate.to_predicate(self.tcx());
+        let predicate = predicate.upcast(self.tcx());
         let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
             locations,
             category,
diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
index 5aa8fe2..b23ad2e 100644
--- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
+++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs
@@ -136,7 +136,7 @@
 
     fn convert(
         &mut self,
-        predicate: ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>,
+        predicate: ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
         constraint_category: ConstraintCategory<'tcx>,
     ) {
         debug!("generate: constraints at: {:#?}", self.locations);
@@ -276,7 +276,7 @@
         &self,
         ty: Ty<'tcx>,
         next_outlives_predicates: &mut Vec<(
-            ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>,
+            ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>,
             ConstraintCategory<'tcx>,
         )>,
     ) -> Ty<'tcx> {
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 2511a15..741ec05 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -11,7 +11,6 @@
 
 use itertools::Itertools;
 use rustc_hir as hir;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::{BoundRegionConversionTime, RegionVariableOrigin};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, Ty};
@@ -74,9 +73,7 @@
                 }),
             );
 
-            let next_ty_var = || {
-                self.infcx.next_ty_var(TypeVariableOrigin { span: body.span, param_def_id: None })
-            };
+            let next_ty_var = || self.infcx.next_ty_var(body.span);
             let output_ty = Ty::new_coroutine(
                 self.tcx(),
                 self.tcx().coroutine_for_closure(mir_def_id),
@@ -101,7 +98,7 @@
                 user_provided_sig.inputs().iter().copied(),
                 output_ty,
                 user_provided_sig.c_variadic,
-                user_provided_sig.unsafety,
+                user_provided_sig.safety,
                 user_provided_sig.abi,
             );
         }
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
index da54566..ccd9fb2 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
@@ -1,4 +1,3 @@
-use rustc_data_structures::vec_linked_list as vll;
 use rustc_index::IndexVec;
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::{Body, Local, Location};
@@ -37,9 +36,12 @@
     /// we add for each local variable.
     first_drop_at: IndexVec<Local, Option<AppearanceIndex>>,
 
-    appearances: IndexVec<AppearanceIndex, Appearance>,
+    appearances: Appearances,
 }
 
+// The `Appearance::next` field effectively embeds a linked list within `Appearances`.
+type Appearances = IndexVec<AppearanceIndex, Appearance>;
+
 struct Appearance {
     point_index: PointIndex,
     next: Option<AppearanceIndex>,
@@ -49,14 +51,34 @@
     pub struct AppearanceIndex {}
 }
 
-impl vll::LinkElem for Appearance {
-    type LinkIndex = AppearanceIndex;
+fn appearances_iter(
+    first: Option<AppearanceIndex>,
+    appearances: &Appearances,
+) -> impl Iterator<Item = AppearanceIndex> + '_ {
+    AppearancesIter { appearances, current: first }
+}
 
-    fn next(elem: &Self) -> Option<AppearanceIndex> {
-        elem.next
+// Iterates over `Appearances` by following `next` fields.
+struct AppearancesIter<'a> {
+    appearances: &'a Appearances,
+    current: Option<AppearanceIndex>,
+}
+
+impl<'a> Iterator for AppearancesIter<'a> {
+    type Item = AppearanceIndex;
+
+    fn next(&mut self) -> Option<AppearanceIndex> {
+        if let Some(c) = self.current {
+            self.current = self.appearances[c].next;
+            Some(c)
+        } else {
+            None
+        }
     }
 }
 
+//-----------------------------------------------------------------------------
+
 impl LocalUseMap {
     pub(crate) fn build(
         live_locals: &[Local],
@@ -86,17 +108,17 @@
     }
 
     pub(crate) fn defs(&self, local: Local) -> impl Iterator<Item = PointIndex> + '_ {
-        vll::iter(self.first_def_at[local], &self.appearances)
+        appearances_iter(self.first_def_at[local], &self.appearances)
             .map(move |aa| self.appearances[aa].point_index)
     }
 
     pub(crate) fn uses(&self, local: Local) -> impl Iterator<Item = PointIndex> + '_ {
-        vll::iter(self.first_use_at[local], &self.appearances)
+        appearances_iter(self.first_use_at[local], &self.appearances)
             .map(move |aa| self.appearances[aa].point_index)
     }
 
     pub(crate) fn drops(&self, local: Local) -> impl Iterator<Item = PointIndex> + '_ {
-        vll::iter(self.first_drop_at[local], &self.appearances)
+        appearances_iter(self.first_drop_at[local], &self.appearances)
             .map(move |aa| self.appearances[aa].point_index)
     }
 }
@@ -146,7 +168,7 @@
     fn insert(
         elements: &DenseLocationMap,
         first_appearance: &mut Option<AppearanceIndex>,
-        appearances: &mut IndexVec<AppearanceIndex, Appearance>,
+        appearances: &mut Appearances,
         location: Location,
     ) {
         let point_index = elements.point_from_location(location);
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
index 7f53022..ccfa9f1 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/polonius.rs
@@ -117,7 +117,7 @@
             let universal_regions = &typeck.borrowck_context.universal_regions;
             typeck.infcx.tcx.for_each_free_region(&local_decl.ty, |region| {
                 let region_vid = universal_regions.to_region_vid(region);
-                facts.use_of_var_derefs_origin.push((local, region_vid));
+                facts.use_of_var_derefs_origin.push((local, region_vid.into()));
             });
         }
     }
@@ -136,7 +136,7 @@
         let universal_regions = &typeck.borrowck_context.universal_regions;
         typeck.infcx.tcx.for_each_free_region(kind, |drop_live_region| {
             let region_vid = universal_regions.to_region_vid(drop_live_region);
-            facts.drop_of_var_derefs_origin.push((local, region_vid));
+            facts.drop_of_var_derefs_origin.push((local, region_vid.into()));
         });
     }
 }
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 13acc67..4e46a0c 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -16,7 +16,6 @@
 use rustc_infer::infer::canonical::QueryRegionConstraints;
 use rustc_infer::infer::outlives::env::RegionBoundPairs;
 use rustc_infer::infer::region_constraints::RegionConstraintData;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::{
     BoundRegion, BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin,
 };
@@ -261,16 +260,14 @@
             |constraint: &OutlivesConstraint<'_>| {
                 if let Some(from_location) = constraint.locations.from_location() {
                     Either::Left(iter::once((
-                        constraint.sup,
-                        constraint.sub,
+                        constraint.sup.into(),
+                        constraint.sub.into(),
                         location_table.mid_index(from_location),
                     )))
                 } else {
-                    Either::Right(
-                        location_table
-                            .all_points()
-                            .map(move |location| (constraint.sup, constraint.sub, location)),
-                    )
+                    Either::Right(location_table.all_points().map(move |location| {
+                        (constraint.sup.into(), constraint.sub.into(), location)
+                    }))
                 }
             },
         ));
@@ -401,7 +398,7 @@
             } else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
                 let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity();
                 let normalized_ty = self.cx.normalize(unnormalized_ty, locations);
-                let literal_ty = constant.const_.ty().builtin_deref(true).unwrap().ty;
+                let literal_ty = constant.const_.ty().builtin_deref(true).unwrap();
 
                 if let Err(terr) = self.cx.eq_types(
                     literal_ty,
@@ -533,8 +530,11 @@
 
         if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
             let tcx = self.tcx();
-            let trait_ref =
-                ty::TraitRef::from_lang_item(tcx, LangItem::Copy, self.last_span, [place_ty.ty]);
+            let trait_ref = ty::TraitRef::new(
+                tcx,
+                tcx.require_lang_item(LangItem::Copy, Some(self.last_span)),
+                [place_ty.ty],
+            );
 
             // To have a `Copy` operand, the type `T` of the
             // value must be `Copy`. Note that we prove that `T: Copy`,
@@ -638,7 +638,7 @@
         match pi {
             ProjectionElem::Deref => {
                 let deref_ty = base_ty.builtin_deref(true);
-                PlaceTy::from_ty(deref_ty.map(|t| t.ty).unwrap_or_else(|| {
+                PlaceTy::from_ty(deref_ty.unwrap_or_else(|| {
                     span_mirbug_and_err!(self, place, "deref of non-pointer {:?}", base_ty)
                 }))
             }
@@ -1274,10 +1274,9 @@
 
                 self.check_rvalue(body, rv, location);
                 if !self.unsized_feature_enabled() {
-                    let trait_ref = ty::TraitRef::from_lang_item(
+                    let trait_ref = ty::TraitRef::new(
                         tcx,
-                        LangItem::Sized,
-                        self.last_span,
+                        tcx.require_lang_item(LangItem::Sized, Some(self.last_span)),
                         [place_ty],
                     );
                     self.prove_trait_ref(
@@ -1926,8 +1925,11 @@
                         Operand::Move(place) => {
                             // Make sure that repeated elements implement `Copy`.
                             let ty = place.ty(body, tcx).ty;
-                            let trait_ref =
-                                ty::TraitRef::from_lang_item(tcx, LangItem::Copy, span, [ty]);
+                            let trait_ref = ty::TraitRef::new(
+                                tcx,
+                                tcx.require_lang_item(LangItem::Copy, Some(span)),
+                                [ty],
+                            );
 
                             self.prove_trait_ref(
                                 trait_ref,
@@ -1940,7 +1942,11 @@
             }
 
             &Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => {
-                let trait_ref = ty::TraitRef::from_lang_item(tcx, LangItem::Sized, span, [ty]);
+                let trait_ref = ty::TraitRef::new(
+                    tcx,
+                    tcx.require_lang_item(LangItem::Sized, Some(span)),
+                    [ty],
+                );
 
                 self.prove_trait_ref(
                     trait_ref,
@@ -1953,7 +1959,11 @@
             Rvalue::ShallowInitBox(operand, ty) => {
                 self.check_operand(operand, location);
 
-                let trait_ref = ty::TraitRef::from_lang_item(tcx, LangItem::Sized, span, [*ty]);
+                let trait_ref = ty::TraitRef::new(
+                    tcx,
+                    tcx.require_lang_item(LangItem::Sized, Some(span)),
+                    [*ty],
+                );
 
                 self.prove_trait_ref(
                     trait_ref,
@@ -1995,13 +2005,13 @@
                         }
                     }
 
-                    CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(unsafety)) => {
+                    CastKind::PointerCoercion(PointerCoercion::ClosureFnPointer(safety)) => {
                         let sig = match op.ty(body, tcx).kind() {
                             ty::Closure(_, args) => args.as_closure().sig(),
                             _ => bug!(),
                         };
                         let ty_fn_ptr_from =
-                            Ty::new_fn_ptr(tcx, tcx.signature_unclosure(sig, *unsafety));
+                            Ty::new_fn_ptr(tcx, tcx.signature_unclosure(sig, *safety));
 
                         if let Err(terr) = self.eq_types(
                             *ty,
@@ -2051,10 +2061,9 @@
 
                     CastKind::PointerCoercion(PointerCoercion::Unsize) => {
                         let &ty = ty;
-                        let trait_ref = ty::TraitRef::from_lang_item(
+                        let trait_ref = ty::TraitRef::new(
                             tcx,
-                            LangItem::CoerceUnsized,
-                            span,
+                            tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)),
                             [op.ty(body, tcx), ty],
                         );
 
@@ -2356,10 +2365,7 @@
                     // Types with regions are comparable if they have a common super-type.
                     ty::RawPtr(_, _) | ty::FnPtr(_) => {
                         let ty_right = right.ty(body, tcx);
-                        let common_ty = self.infcx.next_ty_var(TypeVariableOrigin {
-                            param_def_id: None,
-                            span: body.source_info(location).span,
-                        });
+                        let common_ty = self.infcx.next_ty_var(body.source_info(location).span);
                         self.sub_types(
                             ty_left,
                             common_ty,
@@ -2409,8 +2415,7 @@
                 self.check_operand(op, location);
             }
 
-            Rvalue::BinaryOp(_, box (left, right))
-            | Rvalue::CheckedBinaryOp(_, box (left, right)) => {
+            Rvalue::BinaryOp(_, box (left, right)) => {
                 self.check_operand(left, location);
                 self.check_operand(right, location);
             }
@@ -2437,7 +2442,6 @@
             | Rvalue::Cast(..)
             | Rvalue::ShallowInitBox(..)
             | Rvalue::BinaryOp(..)
-            | Rvalue::CheckedBinaryOp(..)
             | Rvalue::NullaryOp(..)
             | Rvalue::CopyForDeref(..)
             | Rvalue::UnaryOp(..)
@@ -2539,7 +2543,7 @@
             if let Some(borrow_index) = borrow_set.get_index_of(&location) {
                 let region_vid = borrow_region.as_var();
                 all_facts.loan_issued_at.push((
-                    region_vid,
+                    region_vid.into(),
                     borrow_index,
                     location_table.mid_index(location),
                 ));
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 5e4b3e5..cbd8a41 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -1,6 +1,5 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::ErrorGuaranteed;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::NllRegionVariableOrigin;
 use rustc_infer::infer::{ObligationEmittingRelation, StructurallyRelateAliases};
 use rustc_infer::traits::{Obligation, PredicateObligations};
@@ -129,10 +128,7 @@
         // by using `ty_vid rel B` and then finally and end by equating `ty_vid` to
         // the opaque.
         let mut enable_subtyping = |ty, opaque_is_expected| {
-            let ty_vid = infcx.next_ty_var_id_in_universe(
-                TypeVariableOrigin { param_def_id: None, span: self.span() },
-                ty::UniverseIndex::ROOT,
-            );
+            let ty_vid = infcx.next_ty_var_id_in_universe(self.span(), ty::UniverseIndex::ROOT);
 
             let variance = if opaque_is_expected {
                 self.ambient_variance
@@ -550,7 +546,10 @@
         self.type_checker.param_env
     }
 
-    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
         self.register_obligations(
             obligations
                 .into_iter()
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 0f15899..a3d6a1c 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -247,5 +247,3 @@
     .label = not a trait
     .str_lit = try using `#[derive({$sym})]`
     .other = for example, write `#[derive(Debug)]` for `Debug`
-
-builtin_macros_unnameable_test_items = cannot test inner items
diff --git a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
index 064cf7d..4721e74 100644
--- a/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
+++ b/compiler/rustc_builtin_macros/src/alloc_error_handler.rs
@@ -3,7 +3,7 @@
 
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, FnHeader, FnSig, Generics, StmtKind};
-use rustc_ast::{Fn, ItemKind, Stmt, TyKind, Unsafe};
+use rustc_ast::{Fn, ItemKind, Safety, Stmt, TyKind};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::Span;
@@ -78,7 +78,7 @@
     let never = ast::FnRetTy::Ty(cx.ty(span, TyKind::Never));
     let params = thin_vec![cx.param(span, size, ty_usize.clone()), cx.param(span, align, ty_usize)];
     let decl = cx.fn_decl(params, never);
-    let header = FnHeader { unsafety: Unsafe::Yes(span), ..FnHeader::default() };
+    let header = FnHeader { safety: Safety::Unsafe(span), ..FnHeader::default() };
     let sig = FnSig { decl, header, span: span };
 
     let body = Some(cx.block_expr(call));
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 49b1b8c..1a7961b 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -1,6 +1,7 @@
 use crate::errors;
 use crate::util::expr_to_spanned_string;
 use ast::token::IdentIsRaw;
+use lint::BuiltinLintDiag;
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter};
@@ -513,7 +514,7 @@
                     lint::builtin::BAD_ASM_STYLE,
                     find_span(".intel_syntax"),
                     ecx.current_expansion.lint_node_id,
-                    "avoid using `.intel_syntax`, Intel syntax is the default",
+                    BuiltinLintDiag::AvoidUsingIntelSyntax,
                 );
             }
             if template_str.contains(".att_syntax") {
@@ -521,7 +522,7 @@
                     lint::builtin::BAD_ASM_STYLE,
                     find_span(".att_syntax"),
                     ecx.current_expansion.lint_node_id,
-                    "avoid using `.att_syntax`, prefer using `options(att_syntax)` instead",
+                    BuiltinLintDiag::AvoidUsingAttSyntax,
                 );
             }
         }
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index 92efeab..085ea34 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -120,10 +120,13 @@
                 thin_vec![self.cx.attr_nested_word(sym::allow, sym::unused_imports, self.span)],
                 ItemKind::Use(UseTree {
                     prefix: self.cx.path(self.span, self.cx.std_path(&[sym::asserting])),
-                    kind: UseTreeKind::Nested(thin_vec![
-                        nested_tree(self, sym::TryCaptureGeneric),
-                        nested_tree(self, sym::TryCapturePrintable),
-                    ]),
+                    kind: UseTreeKind::Nested {
+                        items: thin_vec![
+                            nested_tree(self, sym::TryCaptureGeneric),
+                            nested_tree(self, sym::TryCapturePrintable),
+                        ],
+                        span: self.span,
+                    },
                     span: self.span,
                 }),
             ),
diff --git a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
index dc73caa..a6457f4 100644
--- a/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs
@@ -31,7 +31,7 @@
                     };
 
                     // We received arguments of type `&T`. Convert them to type `T` by stripping
-                    // any leading `&` or adding `*`. This isn't necessary for type checking, but
+                    // any leading `&`. This isn't necessary for type checking, but
                     // it results in better error messages if something goes wrong.
                     //
                     // Note: for arguments that look like `&{ x }`, which occur with packed
@@ -53,8 +53,7 @@
                                 inner.clone()
                             }
                         } else {
-                            // No leading `&`: add a leading `*`.
-                            cx.expr_deref(field.span, expr.clone())
+                            expr.clone()
                         }
                     };
                     cx.expr_binary(
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index 52c1ba1..217fa5f 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -788,7 +788,7 @@
             Ident::empty(),
             attrs,
             ast::ItemKind::Impl(Box::new(ast::Impl {
-                unsafety: ast::Unsafe::No,
+                safety: ast::Safety::Default,
                 polarity: ast::ImplPolarity::Positive,
                 defaultness: ast::Defaultness::Final,
                 constness: if self.is_const { ast::Const::Yes(DUMMY_SP) } else { ast::Const::No },
@@ -1621,14 +1621,13 @@
                         };
 
                         if let Some(ty) = exception {
-                            cx.sess.psess.buffer_lint_with_diagnostic(
+                            cx.sess.psess.buffer_lint(
                                 BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
                                 sp,
                                 ast::CRATE_NODE_ID,
-                                format!(
-                                    "{ty} slice in a packed struct that derives a built-in trait"
-                                ),
-                                rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive,
+                                rustc_lint_defs::BuiltinLintDiag::ByteSliceInPackedStructWithDerive {
+                                    ty: ty.to_string(),
+                                },
                             );
                         } else {
                             // Wrap the expression in `{...}`, causing a copy.
diff --git a/compiler/rustc_builtin_macros/src/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs
index d6e2d1d..e3a93ae 100644
--- a/compiler/rustc_builtin_macros/src/deriving/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs
@@ -123,7 +123,7 @@
     span: Span,
     assert_path: &[Symbol],
 ) {
-    // Deny anonymous structs or unions to avoid wierd errors.
+    // Deny anonymous structs or unions to avoid weird errors.
     assert!(!ty.kind.is_anon_adt(), "Anonymous structs or unions cannot be type parameters");
     // Generate statement `let _: assert_path<ty>;`.
     let span = cx.with_def_site_ctxt(span);
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 2450ac8..5cb0407 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -7,14 +7,13 @@
 use rustc_ast::{
     Expr, ExprKind, FormatAlignment, FormatArgPosition, FormatArgPositionKind, FormatArgs,
     FormatArgsPiece, FormatArgument, FormatArgumentKind, FormatArguments, FormatCount,
-    FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait,
+    FormatDebugHex, FormatOptions, FormatPlaceholder, FormatSign, FormatTrait, Recovered,
 };
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans};
 use rustc_expand::base::*;
 use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY;
 use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId};
-use rustc_parse::parser::Recovered;
 use rustc_parse_format as parse;
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{BytePos, ErrorGuaranteed, InnerSpan, Span};
@@ -112,7 +111,7 @@
                         _ => return Err(err),
                     }
                 }
-                Ok(Recovered::Yes) => (),
+                Ok(Recovered::Yes(_)) => (),
                 Ok(Recovered::No) => unreachable!(),
             }
         }
@@ -315,7 +314,7 @@
 
     let mut used = vec![false; args.explicit_args().len()];
     let mut invalid_refs = Vec::new();
-    let mut numeric_refences_to_named_arg = Vec::new();
+    let mut numeric_references_to_named_arg = Vec::new();
 
     enum ArgRef<'a> {
         Index(usize),
@@ -336,7 +335,7 @@
                     used[index] = true;
                     if arg.kind.ident().is_some() {
                         // This was a named argument, but it was used as a positional argument.
-                        numeric_refences_to_named_arg.push((index, span, used_as));
+                        numeric_references_to_named_arg.push((index, span, used_as));
                     }
                     Ok(index)
                 } else {
@@ -544,7 +543,7 @@
     // Only check for unused named argument names if there are no other errors to avoid causing
     // too much noise in output errors, such as when a named argument is entirely unused.
     if invalid_refs.is_empty() && !has_unused && !unnamed_arg_after_named_arg {
-        for &(index, span, used_as) in &numeric_refences_to_named_arg {
+        for &(index, span, used_as) in &numeric_references_to_named_arg {
             let (position_sp_to_replace, position_sp_for_msg) = match used_as {
                 Placeholder(pspan) => (span, pspan),
                 Precision => {
@@ -557,7 +556,6 @@
             let arg_name = args.explicit_args()[index].kind.ident().unwrap();
             ecx.buffered_early_lint.push(BufferedEarlyLint {
                 span: arg_name.span.into(),
-                msg: format!("named argument `{}` is not used by name", arg_name.name).into(),
                 node_id: rustc_ast::CRATE_NODE_ID,
                 lint_id: LintId::of(NAMED_ARGUMENTS_USED_POSITIONALLY),
                 diagnostic: BuiltinLintDiag::NamedArgumentUsedPositionally {
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index 307e582..bc2c6de 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -263,13 +263,13 @@
     }
 
     impl Num {
-        fn from_str(s: &str, arg: Option<&str>) -> Self {
+        fn from_str(s: &str, arg: Option<&str>) -> Option<Self> {
             if let Some(arg) = arg {
-                Num::Arg(arg.parse().unwrap_or_else(|_| panic!("invalid format arg `{arg:?}`")))
+                arg.parse().ok().map(|arg| Num::Arg(arg))
             } else if s == "*" {
-                Num::Next
+                Some(Num::Next)
             } else {
-                Num::Num(s.parse().unwrap_or_else(|_| panic!("invalid format num `{s:?}`")))
+                s.parse().ok().map(|num| Num::Num(num))
             }
         }
 
@@ -421,7 +421,10 @@
                             state = Prec;
                             parameter = None;
                             flags = "";
-                            width = Some(Num::from_str(at.slice_between(end).unwrap(), None));
+                            width = at.slice_between(end).and_then(|num| Num::from_str(num, None));
+                            if width.is_none() {
+                                return fallback();
+                            }
                             move_to!(end);
                         }
                         // It's invalid, is what it is.
@@ -452,7 +455,10 @@
                 '1'..='9' => {
                     let end = at_next_cp_while(next, char::is_ascii_digit);
                     state = Prec;
-                    width = Some(Num::from_str(at.slice_between(end).unwrap(), None));
+                    width = at.slice_between(end).and_then(|num| Num::from_str(num, None));
+                    if width.is_none() {
+                        return fallback();
+                    }
                     move_to!(end);
                 }
                 _ => {
@@ -468,7 +474,7 @@
             match end.next_cp() {
                 Some(('$', end2)) => {
                     state = Prec;
-                    width = Some(Num::from_str("", Some(at.slice_between(end).unwrap())));
+                    width = Num::from_str("", at.slice_between(end));
                     move_to!(end2);
                 }
                 _ => {
@@ -500,7 +506,7 @@
                     match end.next_cp() {
                         Some(('$', end2)) => {
                             state = Length;
-                            precision = Some(Num::from_str("*", next.slice_between(end)));
+                            precision = Num::from_str("*", next.slice_between(end));
                             move_to!(end2);
                         }
                         _ => {
@@ -513,7 +519,7 @@
                 '0'..='9' => {
                     let end = at_next_cp_while(next, char::is_ascii_digit);
                     state = Length;
-                    precision = Some(Num::from_str(at.slice_between(end).unwrap(), None));
+                    precision = at.slice_between(end).and_then(|num| Num::from_str(num, None));
                     move_to!(end);
                 }
                 _ => return fallback(),
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index a1630ad..b44ff97 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -6,7 +6,7 @@
 };
 use rustc_ast::ptr::P;
 use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
-use rustc_ast::{Fn, ItemKind, Mutability, Stmt, Ty, TyKind, Unsafe};
+use rustc_ast::{Fn, ItemKind, Mutability, Safety, Stmt, Ty, TyKind};
 use rustc_expand::base::{Annotatable, ExtCtxt};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::Span;
@@ -73,7 +73,7 @@
         let result = self.call_allocator(method.name, args);
         let output_ty = self.ret_ty(&method.output);
         let decl = self.cx.fn_decl(abi_args, ast::FnRetTy::Ty(output_ty));
-        let header = FnHeader { unsafety: Unsafe::Yes(self.span), ..FnHeader::default() };
+        let header = FnHeader { safety: Safety::Unsafe(self.span), ..FnHeader::default() };
         let sig = FnSig { decl, header, span: self.span };
         let body = Some(self.cx.block_expr(result));
         let kind = ItemKind::Fn(Box::new(Fn {
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 47b2ee9..29e9915 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -11,6 +11,7 @@
     resolve_path, DummyResult, ExpandResult, ExtCtxt, MacEager, MacResult, MacroExpanderResult,
 };
 use rustc_expand::module::DirOwnership;
+use rustc_lint_defs::BuiltinLintDiag;
 use rustc_parse::new_parser_from_file;
 use rustc_parse::parser::{ForceCollect, Parser};
 use rustc_session::lint::builtin::INCOMPLETE_INCLUDE;
@@ -147,7 +148,7 @@
                     INCOMPLETE_INCLUDE,
                     self.p.token.span,
                     self.node_id,
-                    "include macro expected single expression in source",
+                    BuiltinLintDiag::IncompleteInclude,
                 );
             }
             Some(expr)
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 1e4bf46..8f96070 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -549,7 +549,7 @@
     let has_should_panic_attr = attr::contains_name(&i.attrs, sym::should_panic);
     let dcx = cx.dcx();
 
-    if let ast::Unsafe::Yes(span) = f.sig.header.unsafety {
+    if let ast::Safety::Unsafe(span) = f.sig.header.safety {
         return Err(dcx.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" }));
     }
 
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 8cf4314..38ac2f1 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -9,6 +9,7 @@
 use rustc_expand::base::{ExtCtxt, ResolverExpand};
 use rustc_expand::expand::{AstFragment, ExpansionConfig};
 use rustc_feature::Features;
+use rustc_lint_defs::BuiltinLintDiag;
 use rustc_session::lint::builtin::UNNAMEABLE_TEST_ITEMS;
 use rustc_session::Session;
 use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency};
@@ -163,7 +164,7 @@
                 UNNAMEABLE_TEST_ITEMS,
                 attr.span,
                 i.id,
-                crate::fluent_generated::builtin_macros_unnameable_test_items,
+                BuiltinLintDiag::UnnameableTestItems,
             );
         }
     }
diff --git a/compiler/rustc_builtin_macros/src/util.rs b/compiler/rustc_builtin_macros/src/util.rs
index 8dc7bc1..652e342 100644
--- a/compiler/rustc_builtin_macros/src/util.rs
+++ b/compiler/rustc_builtin_macros/src/util.rs
@@ -5,7 +5,7 @@
 use rustc_expand::base::{Annotatable, ExpandResult, ExtCtxt};
 use rustc_expand::expand::AstFragment;
 use rustc_feature::AttributeTemplate;
-use rustc_lint_defs::builtin::DUPLICATE_MACRO_ATTRIBUTES;
+use rustc_lint_defs::{builtin::DUPLICATE_MACRO_ATTRIBUTES, BuiltinLintDiag};
 use rustc_parse::{parser, validate_attr};
 use rustc_session::errors::report_lit_error;
 use rustc_span::{BytePos, Span, Symbol};
@@ -46,7 +46,7 @@
                 DUPLICATE_MACRO_ATTRIBUTES,
                 attr.span,
                 ecx.current_expansion.lint_node_id,
-                "duplicated attribute",
+                BuiltinLintDiag::DuplicateMacroAttribute,
             );
         }
     }
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
index a745f28..b7063f3 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
@@ -51,6 +51,14 @@
       if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
       run: rustup set default-host x86_64-pc-windows-gnu
 
+    - name: Use x86_64 compiler on macOS
+      if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin'
+      run: rustup set default-host x86_64-apple-darwin
+
+    - name: Select XCode version
+      if: matrix.os == 'macos-latest'
+      run: sudo xcode-select -s /Applications/Xcode_14.3.1.app
+
     - name: Prepare dependencies
       run: ./y.sh prepare
 
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index 14aa850..1f5a651 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -98,12 +98,20 @@
       if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
       run: rustup set default-host x86_64-pc-windows-gnu
 
+    - name: Use x86_64 compiler on macOS
+      if: matrix.os == 'macos-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-apple-darwin'
+      run: rustup set default-host x86_64-apple-darwin
+
     - name: Install toolchain and emulator
       if: matrix.apt_deps != null
       run: |
         sudo apt-get update
         sudo apt-get install -y ${{ matrix.apt_deps }}
 
+    - name: Select XCode version
+      if: matrix.os == 'macos-latest'
+      run: sudo xcode-select -s /Applications/Xcode_14.3.1.app
+
     - name: Prepare dependencies
       run: ./y.sh prepare
 
@@ -230,12 +238,20 @@
       if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
       run: rustup set default-host x86_64-pc-windows-gnu
 
+    - name: Use x86_64 compiler on macOS
+      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: Select XCode version
+      if: matrix.os == 'macos-latest'
+      run: sudo xcode-select -s /Applications/Xcode_14.3.1.app
+
     - name: Prepare dependencies
       run: ./y.sh prepare
 
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
index 75ea94e..70c214c 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
@@ -20,7 +20,7 @@
       uses: actions/cache@v4
       with:
         path: build/cg_clif
-        key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
+        key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain', 'Cargo.lock') }}
 
     - name: Prepare dependencies
       run: ./y.sh prepare
@@ -43,7 +43,7 @@
       uses: actions/cache@v4
       with:
         path: build/cg_clif
-        key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
+        key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain', 'Cargo.lock') }}
 
     - name: Install ripgrep
       run: |
diff --git a/compiler/rustc_codegen_cranelift/.gitignore b/compiler/rustc_codegen_cranelift/.gitignore
index 7915fa1..5a38f2a 100644
--- a/compiler/rustc_codegen_cranelift/.gitignore
+++ b/compiler/rustc_codegen_cranelift/.gitignore
@@ -1,8 +1,4 @@
 # Build artifacts during normal use
-/y.bin
-/y.bin.dSYM
-/y.exe
-/y.pdb
 /download
 /build
 /dist
diff --git a/compiler/rustc_codegen_cranelift/build_system/Cargo.toml b/compiler/rustc_codegen_cranelift/build_system/Cargo.toml
index f47b9bc..feed2b6 100644
--- a/compiler/rustc_codegen_cranelift/build_system/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/build_system/Cargo.toml
@@ -11,3 +11,6 @@
 unstable-features = [] # for rust-analyzer
 
 # Do not add any dependencies
+
+[profile.dev]
+debug = 1
diff --git a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
index 10c3f9c..196ff8f 100644
--- a/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/build_sysroot.rs
@@ -267,12 +267,16 @@
             prefix.to_str().unwrap()
         ));
     }
+    rustflags.push("-Zunstable-options".to_owned());
+    for (name, values) in EXTRA_CHECK_CFGS {
+        rustflags.push(check_cfg_arg(name, *values));
+    }
     compiler.rustflags.extend(rustflags);
     let mut build_cmd = STANDARD_LIBRARY.build(&compiler, dirs);
     if channel == "release" {
         build_cmd.arg("--release");
     }
-    build_cmd.arg("--features").arg("compiler-builtins-no-asm backtrace panic-unwind");
+    build_cmd.arg("--features").arg("backtrace panic-unwind");
     build_cmd.env("CARGO_PROFILE_RELEASE_DEBUG", "true");
     build_cmd.env("__CARGO_DEFAULT_LIB_METADATA", "cg_clif");
     if compiler.triple.contains("apple") {
@@ -326,3 +330,34 @@
 
     Some(target_libs)
 }
+
+// Copied from https://github.com/rust-lang/rust/blob/4fd98a4b1b100f5329c6efae18031791f64372d2/src/bootstrap/src/utils/helpers.rs#L569-L585
+/// Create a `--check-cfg` argument invocation for a given name
+/// and it's values.
+fn check_cfg_arg(name: &str, values: Option<&[&str]>) -> String {
+    // Creating a string of the values by concatenating each value:
+    // ',values("tvos","watchos")' or '' (nothing) when there are no values.
+    let next = match values {
+        Some(values) => {
+            let mut tmp = values.iter().flat_map(|val| [",", "\"", val, "\""]).collect::<String>();
+
+            tmp.insert_str(1, "values(");
+            tmp.push(')');
+            tmp
+        }
+        None => "".to_string(),
+    };
+    format!("--check-cfg=cfg({name}{next})")
+}
+
+const EXTRA_CHECK_CFGS: &[(&str, Option<&[&str]>)] = &[
+    ("bootstrap", None),
+    ("stdarch_intel_sde", None),
+    ("no_fp_fmt_parse", None),
+    ("no_global_oom_handling", None),
+    ("no_rc", None),
+    ("no_sync", None),
+    ("netbsd10", None),
+    ("backtrace_in_libstd", None),
+    ("target_arch", Some(&["xtensa"])),
+];
diff --git a/compiler/rustc_codegen_cranelift/build_system/main.rs b/compiler/rustc_codegen_cranelift/build_system/main.rs
index cdd2bae..7dbf608 100644
--- a/compiler/rustc_codegen_cranelift/build_system/main.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/main.rs
@@ -147,9 +147,11 @@
 
     let rustup_toolchain_name = match (env::var("CARGO"), env::var("RUSTC"), env::var("RUSTDOC")) {
         (Ok(_), Ok(_), Ok(_)) => None,
-        (Err(_), Err(_), Err(_)) => Some(rustc_info::get_toolchain_name()),
-        _ => {
-            eprintln!("All of CARGO, RUSTC and RUSTDOC need to be set or none must be set");
+        (_, Err(_), Err(_)) => Some(rustc_info::get_toolchain_name()),
+        vars => {
+            eprintln!(
+                "If RUSTC or RUSTDOC is set, both need to be set and in addition CARGO needs to be set: {vars:?}"
+            );
             process::exit(1);
         }
     };
diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs
index 7610490..278f334 100644
--- a/compiler/rustc_codegen_cranelift/build_system/tests.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs
@@ -77,7 +77,7 @@
     ),
     TestCase::build_lib("build.alloc_system", "example/alloc_system.rs", "lib"),
     TestCase::build_bin_and_run("aot.alloc_example", "example/alloc_example.rs", &[]),
-    TestCase::jit_bin("jit.std_example", "example/std_example.rs", ""),
+    TestCase::jit_bin("jit.std_example", "example/std_example.rs", "arg"),
     TestCase::build_bin_and_run("aot.std_example", "example/std_example.rs", &["arg"]),
     TestCase::build_bin_and_run("aot.dst_field_align", "example/dst-field-align.rs", &[]),
     TestCase::build_bin_and_run(
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index efa4be7..aab20f6 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -4,6 +4,7 @@
     never_type,
     linkage,
     extern_types,
+    naked_functions,
     thread_local,
     repr_simd,
     raw_ref_op
@@ -340,6 +341,7 @@
     ))]
     unsafe {
         global_asm_test();
+        naked_test();
     }
 
     // Both statics have a reference that points to the same anonymous allocation.
@@ -395,6 +397,14 @@
     "
 }
 
+#[cfg(all(not(jit), not(no_unstable_features), target_arch = "x86_64"))]
+#[naked]
+extern "C" fn naked_test() {
+    unsafe {
+        asm!("ret", options(noreturn));
+    }
+}
+
 #[repr(C)]
 enum c_void {
     _1,
diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs
index 90d4ab7..7347b2e 100644
--- a/compiler/rustc_codegen_cranelift/example/std_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/std_example.rs
@@ -211,6 +211,21 @@
 extern "C" fn foo(_a: I64X2) {}
 
 #[cfg(target_arch = "x86_64")]
+#[target_feature(enable = "sse4.2")]
+#[cfg(not(jit))]
+unsafe fn test_crc32() {
+    assert!(is_x86_feature_detected!("sse4.2"));
+
+    let a = 42u32;
+    let b = 0xdeadbeefu64;
+
+    assert_eq!(_mm_crc32_u8(a, b as u8), 4135334616);
+    assert_eq!(_mm_crc32_u16(a, b as u16), 1200687288);
+    assert_eq!(_mm_crc32_u32(a, b as u32), 2543798776);
+    assert_eq!(_mm_crc32_u64(a as u64, b as u64), 241952147);
+}
+
+#[cfg(target_arch = "x86_64")]
 #[target_feature(enable = "sse2")]
 unsafe fn test_simd() {
     assert!(is_x86_feature_detected!("sse2"));
@@ -244,10 +259,14 @@
 
     test_mm256_shuffle_epi8();
     test_mm256_permute2x128_si256();
+    test_mm256_permutevar8x32_epi32();
 
     #[rustfmt::skip]
     let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
     assert_eq!(mask1, 1);
+
+    #[cfg(not(jit))]
+    test_crc32();
 }
 
 #[cfg(target_arch = "x86_64")]
@@ -447,6 +466,16 @@
     assert_eq_m256i(r, e);
 }
 
+#[cfg(target_arch = "x86_64")]
+#[target_feature(enable = "avx2")]
+unsafe fn test_mm256_permutevar8x32_epi32() {
+    let a = _mm256_setr_epi32(100, 200, 300, 400, 500, 600, 700, 800);
+    let idx = _mm256_setr_epi32(7, 6, 5, 4, 3, 2, 1, 0);
+    let r = _mm256_setr_epi32(800, 700, 600, 500, 400, 300, 200, 100);
+    let e = _mm256_permutevar8x32_epi32(a, idx);
+    assert_eq_m256i(r, e);
+}
+
 fn test_checked_mul() {
     let u: Option<u8> = u8::from_str_radix("1000", 10).ok();
     assert_eq!(u, None);
diff --git a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
index a72fa2c..c8c7b45 100644
--- a/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
+++ b/compiler/rustc_codegen_cranelift/patches/stdlib-lock.toml
@@ -42,9 +42,9 @@
 
 [[package]]
 name = "cc"
-version = "1.0.90"
+version = "1.0.97"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
+checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
 
 [[package]]
 name = "cfg-if"
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index de340cf..a2ba79c 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2024-04-23"
+channel = "nightly-2024-05-13"
 components = ["rust-src", "rustc-dev", "llvm-tools"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index 8580f45..689cda2 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -44,6 +44,7 @@
 rm tests/ui/abi/mir/mir_codegen_calls_variadic.rs # requires float varargs
 rm tests/ui/abi/variadic-ffi.rs # requires callee side vararg support
 rm -r tests/run-make/c-link-to-rust-va-list-fn # requires callee side vararg support
+rm tests/ui/delegation/fn-header.rs
 
 # unsized locals
 rm -r tests/run-pass-valgrind/unsized-locals
@@ -87,6 +88,7 @@
 rm tests/ui/abi/stack-protector.rs # requires stack protector support
 rm -r tests/run-make/emit-stack-sizes # requires support for -Z emit-stack-sizes
 rm -r tests/run-make/optimization-remarks-dir # remarks are LLVM specific
+rm -r tests/run-make/print-to-output # requires --print relocation-models
 
 # requires asm, llvm-ir and/or llvm-bc emit support
 # =============================================
@@ -151,7 +153,7 @@
          let mut cmd = setup_common();
 -        let target_rpath_dir = env::var_os("TARGET_RPATH_DIR").unwrap();
 -        cmd.arg(format!("-L{}", target_rpath_dir.to_string_lossy()));
-         Self { cmd }
+         Self { cmd, stdin: None }
      }
 
 EOF
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 6f346af..4bcef15 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -412,7 +412,7 @@
                     Err(instance) => Some(instance),
                 }
             }
-            InstanceDef::DropGlue(_, None) => {
+            InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None) => {
                 // empty drop glue - a nop.
                 let dest = target.expect("Non terminating drop_in_place_real???");
                 let ret_block = fx.get_block(dest);
@@ -597,7 +597,9 @@
     let ty = drop_place.layout().ty;
     let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx);
 
-    if let ty::InstanceDef::DropGlue(_, None) = drop_instance.def {
+    if let ty::InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None) =
+        drop_instance.def
+    {
         // we don't actually need to drop anything
     } else {
         match ty.kind() {
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index e3d050d..8d778f7 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -6,6 +6,7 @@
 use cranelift_module::ModuleError;
 use rustc_ast::InlineAsmOptions;
 use rustc_index::IndexVec;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::layout::FnAbiOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -14,6 +15,7 @@
 
 use crate::constant::ConstantCx;
 use crate::debuginfo::{FunctionDebugContext, TypeDebugContext};
+use crate::inline_asm::codegen_naked_asm;
 use crate::prelude::*;
 use crate::pretty_clif::CommentWriter;
 
@@ -32,7 +34,7 @@
     cached_func: Function,
     module: &mut dyn Module,
     instance: Instance<'tcx>,
-) -> CodegenedFunction {
+) -> Option<CodegenedFunction> {
     debug_assert!(!instance.args.has_infer());
 
     let symbol_name = tcx.symbol_name(instance).name.to_string();
@@ -48,6 +50,37 @@
         String::from_utf8_lossy(&buf).into_owned()
     });
 
+    if tcx.codegen_fn_attrs(instance.def_id()).flags.contains(CodegenFnAttrFlags::NAKED) {
+        assert_eq!(mir.basic_blocks.len(), 1);
+        assert!(mir.basic_blocks[START_BLOCK].statements.is_empty());
+
+        match &mir.basic_blocks[START_BLOCK].terminator().kind {
+            TerminatorKind::InlineAsm {
+                template,
+                operands,
+                options,
+                line_spans: _,
+                targets: _,
+                unwind: _,
+            } => {
+                codegen_naked_asm(
+                    tcx,
+                    cx,
+                    module,
+                    instance,
+                    mir.basic_blocks[START_BLOCK].terminator().source_info.span,
+                    &symbol_name,
+                    template,
+                    operands,
+                    *options,
+                );
+            }
+            _ => unreachable!(),
+        }
+
+        return None;
+    }
+
     // Declare function
     let sig = get_function_sig(tcx, module.target_config().default_call_conv, instance);
     let func_id = module.declare_function(&symbol_name, Linkage::Local, &sig).unwrap();
@@ -128,7 +161,7 @@
     // Verify function
     verify_func(tcx, &clif_comments, &func);
 
-    CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx }
+    Some(CodegenedFunction { symbol_name, func_id, func, clif_comments, func_debug_cx })
 }
 
 pub(crate) fn compile_fn(
@@ -576,14 +609,11 @@
                     let lhs = codegen_operand(fx, &lhs_rhs.0);
                     let rhs = codegen_operand(fx, &lhs_rhs.1);
 
-                    let res = crate::num::codegen_binop(fx, bin_op, lhs, rhs);
-                    lval.write_cvalue(fx, res);
-                }
-                Rvalue::CheckedBinaryOp(bin_op, ref lhs_rhs) => {
-                    let lhs = codegen_operand(fx, &lhs_rhs.0);
-                    let rhs = codegen_operand(fx, &lhs_rhs.1);
-
-                    let res = crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs);
+                    let res = if let Some(bin_op) = bin_op.overflowing_to_wrapping() {
+                        crate::num::codegen_checked_int_binop(fx, bin_op, lhs, rhs)
+                    } else {
+                        crate::num::codegen_binop(fx, bin_op, lhs, rhs)
+                    };
                     lval.write_cvalue(fx, res);
                 }
                 Rvalue::UnaryOp(un_op, ref operand) => {
@@ -670,11 +700,8 @@
                     let to_ty = fx.monomorphize(to_ty);
 
                     fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
-                        ty.builtin_deref(true).is_some_and(
-                            |ty::TypeAndMut { ty: pointee_ty, mutbl: _ }| {
-                                has_ptr_meta(fx.tcx, pointee_ty)
-                            },
-                        )
+                        ty.builtin_deref(true)
+                            .is_some_and(|pointee_ty| has_ptr_meta(fx.tcx, pointee_ty))
                     }
 
                     if is_fat_ptr(fx, from_ty) {
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index 4a5ef35..e16b776 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -70,6 +70,7 @@
         }
         BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne | BinOp::Cmp => None,
         BinOp::Shl | BinOp::ShlUnchecked | BinOp::Shr | BinOp::ShrUnchecked => None,
+        BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => unreachable!(),
     }
 }
 
@@ -132,6 +133,7 @@
             Some(out_place.to_cvalue(fx))
         }
         BinOp::AddUnchecked | BinOp::SubUnchecked | BinOp::MulUnchecked => unreachable!(),
+        BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => unreachable!(),
         BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
         BinOp::Div | BinOp::Rem => unreachable!(),
         BinOp::Cmp => unreachable!(),
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index 2a24d61..21d0cd2 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -7,7 +7,7 @@
 use rustc_middle::ty::TypeFoldable;
 use rustc_span::source_map::Spanned;
 use rustc_target::abi::call::FnAbi;
-use rustc_target::abi::{Integer, Primitive};
+use rustc_target::abi::{Float, Integer, Primitive};
 use rustc_target::spec::{HasTargetSpec, Target};
 
 use crate::constant::ConstantCx;
@@ -32,10 +32,12 @@
             Integer::I64 => types::I64,
             Integer::I128 => types::I128,
         },
-        Primitive::F16 => unimplemented!("f16_f128"),
-        Primitive::F32 => types::F32,
-        Primitive::F64 => types::F64,
-        Primitive::F128 => unimplemented!("f16_f128"),
+        Primitive::Float(float) => match float {
+            Float::F16 => unimplemented!("f16_f128"),
+            Float::F32 => types::F32,
+            Float::F64 => types::F64,
+            Float::F128 => unimplemented!("f16_f128"),
+        },
         // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
         Primitive::Pointer(_) => pointer_ty(tcx),
     }
diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
index 9678969..a73860c 100644
--- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
+++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
@@ -6,7 +6,7 @@
 // FIXME don't panic when a worker thread panics
 
 pub(super) struct ConcurrencyLimiter {
-    helper_thread: Option<HelperThread>,
+    helper_thread: Option<Mutex<HelperThread>>,
     state: Arc<Mutex<state::ConcurrencyLimiterState>>,
     available_token_condvar: Arc<Condvar>,
     finished: bool,
@@ -39,14 +39,14 @@
             })
             .unwrap();
         ConcurrencyLimiter {
-            helper_thread: Some(helper_thread),
+            helper_thread: Some(Mutex::new(helper_thread)),
             state,
             available_token_condvar,
             finished: false,
         }
     }
 
-    pub(super) fn acquire(&mut self, dcx: &rustc_errors::DiagCtxt) -> ConcurrencyLimiterToken {
+    pub(super) fn acquire(&self, dcx: &rustc_errors::DiagCtxt) -> ConcurrencyLimiterToken {
         let mut state = self.state.lock().unwrap();
         loop {
             state.assert_invariants();
@@ -73,16 +73,11 @@
                 }
             }
 
-            self.helper_thread.as_mut().unwrap().request_token();
+            self.helper_thread.as_ref().unwrap().lock().unwrap().request_token();
             state = self.available_token_condvar.wait(state).unwrap();
         }
     }
 
-    pub(super) fn job_already_done(&mut self) {
-        let mut state = self.state.lock().unwrap();
-        state.job_already_done();
-    }
-
     pub(crate) fn finished(mut self) {
         self.helper_thread.take();
 
@@ -190,14 +185,6 @@
             self.assert_invariants();
         }
 
-        pub(super) fn job_already_done(&mut self) {
-            self.assert_invariants();
-            self.pending_jobs -= 1;
-            self.assert_invariants();
-            self.drop_excess_capacity();
-            self.assert_invariants();
-        }
-
         pub(super) fn poison(&mut self, error: String) {
             self.poisoned = true;
             self.stored_error = Some(error);
diff --git a/compiler/rustc_codegen_cranelift/src/config.rs b/compiler/rustc_codegen_cranelift/src/config.rs
index 9e92d65..12bce68 100644
--- a/compiler/rustc_codegen_cranelift/src/config.rs
+++ b/compiler/rustc_codegen_cranelift/src/config.rs
@@ -64,8 +64,13 @@
         BackendConfig {
             codegen_mode: CodegenMode::Aot,
             jit_args: {
-                let args = std::env::var("CG_CLIF_JIT_ARGS").unwrap_or_else(|_| String::new());
-                args.split(' ').map(|arg| arg.to_string()).collect()
+                match std::env::var("CG_CLIF_JIT_ARGS") {
+                    Ok(args) => args.split(' ').map(|arg| arg.to_string()).collect(),
+                    Err(std::env::VarError::NotPresent) => vec![],
+                    Err(std::env::VarError::NotUnicode(s)) => {
+                        panic!("CG_CLIF_JIT_ARGS not unicode: {:?}", s);
+                    }
+                }
             },
             enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"),
             disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"),
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index cdf499a..64e83e4 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -258,7 +258,7 @@
 ) -> DataId {
     let attrs = tcx.codegen_fn_attrs(def_id);
 
-    let instance = Instance::mono(tcx, def_id).polymorphize(tcx);
+    let instance = Instance::mono(tcx, def_id);
     let symbol_name = tcx.symbol_name(instance).name;
 
     if let Some(import_linkage) = attrs.import_linkage {
diff --git a/compiler/rustc_codegen_cranelift/src/discriminant.rs b/compiler/rustc_codegen_cranelift/src/discriminant.rs
index 6703846..e7ac084 100644
--- a/compiler/rustc_codegen_cranelift/src/discriminant.rs
+++ b/compiler/rustc_codegen_cranelift/src/discriminant.rs
@@ -28,16 +28,20 @@
         } => {
             let ptr = place.place_field(fx, FieldIdx::new(tag_field));
             let to = layout.ty.discriminant_for_variant(fx.tcx, variant_index).unwrap().val;
-            let to = if ptr.layout().abi.is_signed() {
-                ty::ScalarInt::try_from_int(
-                    ptr.layout().size.sign_extend(to) as i128,
-                    ptr.layout().size,
-                )
-                .unwrap()
-            } else {
-                ty::ScalarInt::try_from_uint(to, ptr.layout().size).unwrap()
+            let to = match ptr.layout().ty.kind() {
+                ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
+                    let lsb = fx.bcx.ins().iconst(types::I64, to as u64 as i64);
+                    let msb = fx.bcx.ins().iconst(types::I64, (to >> 64) as u64 as i64);
+                    fx.bcx.ins().iconcat(lsb, msb)
+                }
+                ty::Uint(_) | ty::Int(_) => {
+                    let clif_ty = fx.clif_type(ptr.layout().ty).unwrap();
+                    let raw_val = ptr.layout().size.truncate(to);
+                    fx.bcx.ins().iconst(clif_ty, raw_val as i64)
+                }
+                _ => unreachable!(),
             };
-            let discr = CValue::const_val(fx, ptr.layout(), to);
+            let discr = CValue::by_val(to, ptr.layout());
             ptr.write_cvalue(fx, discr);
         }
         Variants::Multiple {
@@ -85,16 +89,21 @@
                 .ty
                 .discriminant_for_variant(fx.tcx, *index)
                 .map_or(u128::from(index.as_u32()), |discr| discr.val);
-            let discr_val = if dest_layout.abi.is_signed() {
-                ty::ScalarInt::try_from_int(
-                    dest_layout.size.sign_extend(discr_val) as i128,
-                    dest_layout.size,
-                )
-                .unwrap()
-            } else {
-                ty::ScalarInt::try_from_uint(discr_val, dest_layout.size).unwrap()
+
+            let val = match dest_layout.ty.kind() {
+                ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
+                    let lsb = fx.bcx.ins().iconst(types::I64, discr_val as u64 as i64);
+                    let msb = fx.bcx.ins().iconst(types::I64, (discr_val >> 64) as u64 as i64);
+                    fx.bcx.ins().iconcat(lsb, msb)
+                }
+                ty::Uint(_) | ty::Int(_) => {
+                    let clif_ty = fx.clif_type(dest_layout.ty).unwrap();
+                    let raw_val = dest_layout.size.truncate(discr_val);
+                    fx.bcx.ins().iconst(clif_ty, raw_val as i64)
+                }
+                _ => unreachable!(),
             };
-            let res = CValue::const_val(fx, dest_layout, discr_val);
+            let res = CValue::by_val(val, dest_layout);
             dest.write_cvalue(fx, res);
             return;
         }
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index e8c9648..fce4690 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -15,6 +15,7 @@
 use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind};
 use rustc_data_structures::profiling::SelfProfilerRef;
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::sync::{par_map, IntoDynSyncSend};
 use rustc_metadata::fs::copy_to_stdout;
 use rustc_metadata::EncodedMetadata;
 use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
@@ -481,15 +482,16 @@
             for (mono_item, _) in mono_items {
                 match mono_item {
                     MonoItem::Fn(inst) => {
-                        let codegened_function = crate::base::codegen_fn(
+                        if let Some(codegened_function) = crate::base::codegen_fn(
                             tcx,
                             &mut cx,
                             &mut type_dbg,
                             Function::new(),
                             &mut module,
                             inst,
-                        );
-                        codegened_functions.push(codegened_function);
+                        ) {
+                            codegened_functions.push(codegened_function);
+                        }
                     }
                     MonoItem::Static(def_id) => {
                         let data_id = crate::constant::codegen_static(tcx, &mut module, def_id);
@@ -604,39 +606,39 @@
 
     let global_asm_config = Arc::new(crate::global_asm::GlobalAsmConfig::new(tcx));
 
-    let mut concurrency_limiter = ConcurrencyLimiter::new(tcx.sess, cgus.len());
+    let (todo_cgus, done_cgus) =
+        cgus.into_iter().enumerate().partition::<Vec<_>, _>(|&(i, _)| match cgu_reuse[i] {
+            _ if backend_config.disable_incr_cache => true,
+            CguReuse::No => true,
+            CguReuse::PreLto | CguReuse::PostLto => false,
+        });
+
+    let concurrency_limiter = IntoDynSyncSend(ConcurrencyLimiter::new(tcx.sess, todo_cgus.len()));
 
     let modules = tcx.sess.time("codegen mono items", || {
-        cgus.iter()
-            .enumerate()
-            .map(|(i, cgu)| {
-                let cgu_reuse =
-                    if backend_config.disable_incr_cache { CguReuse::No } else { cgu_reuse[i] };
-                match cgu_reuse {
-                    CguReuse::No => {
-                        let dep_node = cgu.codegen_dep_node(tcx);
-                        tcx.dep_graph
-                            .with_task(
-                                dep_node,
-                                tcx,
-                                (
-                                    backend_config.clone(),
-                                    global_asm_config.clone(),
-                                    cgu.name(),
-                                    concurrency_limiter.acquire(tcx.dcx()),
-                                ),
-                                module_codegen,
-                                Some(rustc_middle::dep_graph::hash_result),
-                            )
-                            .0
-                    }
-                    CguReuse::PreLto | CguReuse::PostLto => {
-                        concurrency_limiter.job_already_done();
-                        OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu))
-                    }
-                }
-            })
-            .collect::<Vec<_>>()
+        let mut modules: Vec<_> = par_map(todo_cgus, |(_, cgu)| {
+            let dep_node = cgu.codegen_dep_node(tcx);
+            tcx.dep_graph
+                .with_task(
+                    dep_node,
+                    tcx,
+                    (
+                        backend_config.clone(),
+                        global_asm_config.clone(),
+                        cgu.name(),
+                        concurrency_limiter.acquire(tcx.dcx()),
+                    ),
+                    module_codegen,
+                    Some(rustc_middle::dep_graph::hash_result),
+                )
+                .0
+        });
+        modules.extend(
+            done_cgus
+                .into_iter()
+                .map(|(_, cgu)| OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu))),
+        );
+        modules
     });
 
     let mut allocator_module = make_module(tcx.sess, &backend_config, "allocator_shim".to_string());
@@ -705,6 +707,6 @@
         metadata_module,
         metadata,
         crate_info: CrateInfo::new(tcx, target_cpu),
-        concurrency_limiter,
+        concurrency_limiter: concurrency_limiter.0,
     })
 }
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index 929fa92..4b14913 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -83,13 +83,6 @@
     );
 
     crate::allocator::codegen(tcx, &mut jit_module, &mut cx.unwind_context);
-    crate::main_shim::maybe_create_entry_wrapper(
-        tcx,
-        &mut jit_module,
-        &mut cx.unwind_context,
-        true,
-        true,
-    );
 
     (jit_module, cx)
 }
@@ -153,6 +146,14 @@
         tcx.dcx().fatal("Inline asm is not supported in JIT mode");
     }
 
+    crate::main_shim::maybe_create_entry_wrapper(
+        tcx,
+        &mut jit_module,
+        &mut cx.unwind_context,
+        true,
+        true,
+    );
+
     tcx.dcx().abort_if_errors();
 
     jit_module.finalize_definitions().unwrap();
@@ -231,16 +232,16 @@
             crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name));
 
         let cached_func = std::mem::replace(&mut cached_context.func, Function::new());
-        let codegened_func = crate::base::codegen_fn(
+        if let Some(codegened_func) = crate::base::codegen_fn(
             tcx,
             cx,
             &mut TypeDebugContext::default(),
             cached_func,
             module,
             instance,
-        );
-
-        crate::base::compile_fn(cx, cached_context, module, codegened_func);
+        ) {
+            crate::base::compile_fn(cx, cached_context, module, codegened_func);
+        }
     });
 }
 
diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
index 12e90b5..fb0eed0 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
@@ -5,6 +5,7 @@
 //! [`codegen_static`]: crate::constant::codegen_static
 
 use rustc_data_structures::profiling::SelfProfilerRef;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::mir::mono::{MonoItem, MonoItemData};
 
 use crate::prelude::*;
@@ -33,7 +34,20 @@
                         data.visibility,
                         is_compiler_builtins,
                     );
-                    module.declare_function(name, linkage, &sig).unwrap();
+                    let is_naked = tcx
+                        .codegen_fn_attrs(instance.def_id())
+                        .flags
+                        .contains(CodegenFnAttrFlags::NAKED);
+                    module
+                        .declare_function(
+                            name,
+                            // Naked functions are defined in a separate object
+                            // file from the codegen unit rustc expects them to
+                            // be defined in.
+                            if is_naked { Linkage::Import } else { linkage },
+                            &sig,
+                        )
+                        .unwrap();
                 }
                 MonoItem::Static(_) | MonoItem::GlobalAsm(_) => {}
             }
diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs
index 5a0cd39..0c99a5c 100644
--- a/compiler/rustc_codegen_cranelift/src/global_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs
@@ -81,7 +81,7 @@
                                 );
                             }
 
-                            let instance = Instance::mono(tcx, def_id).polymorphize(tcx);
+                            let instance = Instance::mono(tcx, def_id);
                             let symbol = tcx.symbol_name(instance);
                             global_asm.push_str(symbol.name);
                         }
diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
index 28b92f7..2de804f 100644
--- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs
@@ -127,7 +127,7 @@
             }
             InlineAsmOperand::SymStatic { def_id } => {
                 assert!(fx.tcx.is_static(def_id));
-                let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
+                let instance = Instance::mono(fx.tcx, def_id);
                 CInlineAsmOperand::Symbol { symbol: fx.tcx.symbol_name(instance).name.to_owned() }
             }
             InlineAsmOperand::Label { .. } => {
@@ -169,6 +169,7 @@
         stack_slots_input: Vec::new(),
         stack_slots_output: Vec::new(),
         stack_slot_size: Size::from_bytes(0),
+        is_naked: false,
     };
     asm_gen.allocate_registers();
     asm_gen.allocate_stack_slots();
@@ -209,6 +210,121 @@
     call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs);
 }
 
+pub(crate) fn codegen_naked_asm<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    cx: &mut crate::CodegenCx,
+    module: &mut dyn Module,
+    instance: Instance<'tcx>,
+    span: Span,
+    symbol_name: &str,
+    template: &[InlineAsmTemplatePiece],
+    operands: &[InlineAsmOperand<'tcx>],
+    options: InlineAsmOptions,
+) {
+    // FIXME add .eh_frame unwind info directives
+
+    let operands = operands
+        .iter()
+        .map(|operand| match *operand {
+            InlineAsmOperand::In { .. }
+            | InlineAsmOperand::Out { .. }
+            | InlineAsmOperand::InOut { .. } => {
+                span_bug!(span, "invalid operand type for naked asm")
+            }
+            InlineAsmOperand::Const { ref value } => {
+                let cv = instance.instantiate_mir_and_normalize_erasing_regions(
+                    tcx,
+                    ty::ParamEnv::reveal_all(),
+                    ty::EarlyBinder::bind(value.const_),
+                );
+                let const_value = cv
+                    .eval(tcx, ty::ParamEnv::reveal_all(), value.span)
+                    .expect("erroneous constant missed by mono item collection");
+
+                let value = rustc_codegen_ssa::common::asm_const_to_str(
+                    tcx,
+                    span,
+                    const_value,
+                    RevealAllLayoutCx(tcx).layout_of(cv.ty()),
+                );
+                CInlineAsmOperand::Const { value }
+            }
+            InlineAsmOperand::SymFn { ref value } => {
+                if cfg!(not(feature = "inline_asm_sym")) {
+                    tcx.dcx()
+                        .span_err(span, "asm! and global_asm! sym operands are not yet supported");
+                }
+
+                let const_ = instance.instantiate_mir_and_normalize_erasing_regions(
+                    tcx,
+                    ty::ParamEnv::reveal_all(),
+                    ty::EarlyBinder::bind(value.const_),
+                );
+                if let ty::FnDef(def_id, args) = *const_.ty().kind() {
+                    let instance = ty::Instance::resolve_for_fn_ptr(
+                        tcx,
+                        ty::ParamEnv::reveal_all(),
+                        def_id,
+                        args,
+                    )
+                    .unwrap();
+                    let symbol = tcx.symbol_name(instance);
+
+                    // Pass a wrapper rather than the function itself as the function itself may not
+                    // be exported from the main codegen unit and may thus be unreachable from the
+                    // object file created by an external assembler.
+                    let inline_asm_index = cx.inline_asm_index.get();
+                    cx.inline_asm_index.set(inline_asm_index + 1);
+                    let wrapper_name = format!(
+                        "__inline_asm_{}_wrapper_n{}",
+                        cx.cgu_name.as_str().replace('.', "__").replace('-', "_"),
+                        inline_asm_index
+                    );
+                    let sig =
+                        get_function_sig(tcx, module.target_config().default_call_conv, instance);
+                    create_wrapper_function(
+                        module,
+                        &mut cx.unwind_context,
+                        sig,
+                        &wrapper_name,
+                        symbol.name,
+                    );
+
+                    CInlineAsmOperand::Symbol { symbol: wrapper_name }
+                } else {
+                    span_bug!(span, "invalid type for asm sym (fn)");
+                }
+            }
+            InlineAsmOperand::SymStatic { def_id } => {
+                assert!(tcx.is_static(def_id));
+                let instance = Instance::mono(tcx, def_id);
+                CInlineAsmOperand::Symbol { symbol: tcx.symbol_name(instance).name.to_owned() }
+            }
+            InlineAsmOperand::Label { .. } => {
+                span_bug!(span, "asm! label operands are not yet supported");
+            }
+        })
+        .collect::<Vec<_>>();
+
+    let asm_gen = InlineAssemblyGenerator {
+        tcx,
+        arch: tcx.sess.asm_arch.unwrap(),
+        enclosing_def_id: instance.def_id(),
+        template,
+        operands: &operands,
+        options,
+        registers: Vec::new(),
+        stack_slots_clobber: Vec::new(),
+        stack_slots_input: Vec::new(),
+        stack_slots_output: Vec::new(),
+        stack_slot_size: Size::from_bytes(0),
+        is_naked: true,
+    };
+
+    let generated_asm = asm_gen.generate_asm_wrapper(symbol_name);
+    cx.global_asm.push_str(&generated_asm);
+}
+
 struct InlineAssemblyGenerator<'a, 'tcx> {
     tcx: TyCtxt<'tcx>,
     arch: InlineAsmArch,
@@ -221,10 +337,13 @@
     stack_slots_input: Vec<Option<Size>>,
     stack_slots_output: Vec<Option<Size>>,
     stack_slot_size: Size,
+    is_naked: bool,
 }
 
 impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
     fn allocate_registers(&mut self) {
+        assert!(!self.is_naked);
+
         let sess = self.tcx.sess;
         let map = allocatable_registers(
             self.arch,
@@ -348,6 +467,8 @@
     }
 
     fn allocate_stack_slots(&mut self) {
+        assert!(!self.is_naked);
+
         let mut slot_size = Size::from_bytes(0);
         let mut slots_clobber = vec![None; self.operands.len()];
         let mut slots_input = vec![None; self.operands.len()];
@@ -468,30 +589,32 @@
         if is_x86 {
             generated_asm.push_str(".intel_syntax noprefix\n");
         }
-        Self::prologue(&mut generated_asm, self.arch);
+        if !self.is_naked {
+            Self::prologue(&mut generated_asm, self.arch);
 
-        // Save clobbered registers
-        if !self.options.contains(InlineAsmOptions::NORETURN) {
+            // Save clobbered registers
+            if !self.options.contains(InlineAsmOptions::NORETURN) {
+                for (reg, slot) in self
+                    .registers
+                    .iter()
+                    .zip(self.stack_slots_clobber.iter().copied())
+                    .filter_map(|(r, s)| r.zip(s))
+                {
+                    Self::save_register(&mut generated_asm, self.arch, reg, slot);
+                }
+            }
+
+            // Write input registers
             for (reg, slot) in self
                 .registers
                 .iter()
-                .zip(self.stack_slots_clobber.iter().copied())
+                .zip(self.stack_slots_input.iter().copied())
                 .filter_map(|(r, s)| r.zip(s))
             {
-                Self::save_register(&mut generated_asm, self.arch, reg, slot);
+                Self::restore_register(&mut generated_asm, self.arch, reg, slot);
             }
         }
 
-        // Write input registers
-        for (reg, slot) in self
-            .registers
-            .iter()
-            .zip(self.stack_slots_input.iter().copied())
-            .filter_map(|(r, s)| r.zip(s))
-        {
-            Self::restore_register(&mut generated_asm, self.arch, reg, slot);
-        }
-
         if is_x86 && self.options.contains(InlineAsmOptions::ATT_SYNTAX) {
             generated_asm.push_str(".att_syntax\n");
         }
@@ -553,30 +676,32 @@
             generated_asm.push_str(".intel_syntax noprefix\n");
         }
 
-        if !self.options.contains(InlineAsmOptions::NORETURN) {
-            // Read output registers
-            for (reg, slot) in self
-                .registers
-                .iter()
-                .zip(self.stack_slots_output.iter().copied())
-                .filter_map(|(r, s)| r.zip(s))
-            {
-                Self::save_register(&mut generated_asm, self.arch, reg, slot);
-            }
+        if !self.is_naked {
+            if !self.options.contains(InlineAsmOptions::NORETURN) {
+                // Read output registers
+                for (reg, slot) in self
+                    .registers
+                    .iter()
+                    .zip(self.stack_slots_output.iter().copied())
+                    .filter_map(|(r, s)| r.zip(s))
+                {
+                    Self::save_register(&mut generated_asm, self.arch, reg, slot);
+                }
 
-            // Restore clobbered registers
-            for (reg, slot) in self
-                .registers
-                .iter()
-                .zip(self.stack_slots_clobber.iter().copied())
-                .filter_map(|(r, s)| r.zip(s))
-            {
-                Self::restore_register(&mut generated_asm, self.arch, reg, slot);
-            }
+                // Restore clobbered registers
+                for (reg, slot) in self
+                    .registers
+                    .iter()
+                    .zip(self.stack_slots_clobber.iter().copied())
+                    .filter_map(|(r, s)| r.zip(s))
+                {
+                    Self::restore_register(&mut generated_asm, self.arch, reg, slot);
+                }
 
-            Self::epilogue(&mut generated_asm, self.arch);
-        } else {
-            Self::epilogue_noreturn(&mut generated_asm, self.arch);
+                Self::epilogue(&mut generated_asm, self.arch);
+            } else {
+                Self::epilogue_noreturn(&mut generated_asm, self.arch);
+            }
         }
 
         if is_x86 {
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index 8df83c7..27b55ec 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -374,6 +374,21 @@
                 }
             }
         }
+        "llvm.x86.avx2.permd" => {
+            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_permutevar8x32_epi32
+            intrinsic_args!(fx, args => (a, idx); intrinsic);
+
+            for j in 0..=7 {
+                let index = idx.value_typed_lane(fx, fx.tcx.types.u32, j).load_scalar(fx);
+                let index = fx.bcx.ins().uextend(fx.pointer_type, index);
+                let value = a.value_lane_dyn(fx, index).load_scalar(fx);
+                ret.place_typed_lane(fx, fx.tcx.types.u32, j).to_ptr().store(
+                    fx,
+                    value,
+                    MemFlags::trusted(),
+                );
+            }
+        }
         "llvm.x86.avx2.vperm2i128"
         | "llvm.x86.avx.vperm2f128.ps.256"
         | "llvm.x86.avx.vperm2f128.pd.256" => {
@@ -832,6 +847,43 @@
             }
         }
 
+        "llvm.x86.sse42.crc32.32.8"
+        | "llvm.x86.sse42.crc32.32.16"
+        | "llvm.x86.sse42.crc32.32.32"
+        | "llvm.x86.sse42.crc32.64.64" => {
+            // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#ig_expand=1419&text=_mm_crc32_u32
+            intrinsic_args!(fx, args => (crc, v); intrinsic);
+
+            let crc = crc.load_scalar(fx);
+            let v = v.load_scalar(fx);
+
+            let asm = match intrinsic {
+                "llvm.x86.sse42.crc32.32.8" => "crc32 eax, dl",
+                "llvm.x86.sse42.crc32.32.16" => "crc32 eax, dx",
+                "llvm.x86.sse42.crc32.32.32" => "crc32 eax, edx",
+                "llvm.x86.sse42.crc32.64.64" => "crc32 rax, rdx",
+                _ => unreachable!(),
+            };
+
+            codegen_inline_asm_inner(
+                fx,
+                &[InlineAsmTemplatePiece::String(asm.to_string())],
+                &[
+                    CInlineAsmOperand::InOut {
+                        reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)),
+                        _late: true,
+                        in_value: crc,
+                        out_place: Some(ret),
+                    },
+                    CInlineAsmOperand::In {
+                        reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)),
+                        value: v,
+                    },
+                ],
+                InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM,
+            );
+        }
+
         "llvm.x86.sse42.pcmpestri128" => {
             // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpestri&ig_expand=939
             intrinsic_args!(fx, args => (a, la, b, lb, _imm8); intrinsic);
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 79a9050..cafdc05 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -586,7 +586,7 @@
             intrinsic_args!(fx, args => (base, offset); intrinsic);
             let offset = offset.load_scalar(fx);
 
-            let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty;
+            let pointee_ty = base.layout().ty.builtin_deref(true).unwrap();
             let pointee_size = fx.layout_of(pointee_ty).size.bytes();
             let ptr_diff = if pointee_size != 1 {
                 fx.bcx.ins().imul_imm(offset, pointee_size as i64)
@@ -610,7 +610,7 @@
             let val = val.load_scalar(fx);
             let count = count.load_scalar(fx);
 
-            let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap().ty;
+            let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap();
             let pointee_size = fx.layout_of(pointee_ty).size.bytes();
             let count = if pointee_size != 1 {
                 fx.bcx.ins().imul_imm(count, pointee_size as i64)
@@ -715,7 +715,7 @@
 
             // Cranelift treats loads as volatile by default
             // FIXME correctly handle unaligned_volatile_load
-            let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
+            let inner_layout = fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap());
             let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), inner_layout);
             ret.write_cvalue(fx, val);
         }
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 67f9d83..b17f191 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -348,6 +348,7 @@
         | sym::simd_bswap
         | sym::simd_bitreverse
         | sym::simd_ctlz
+        | sym::simd_ctpop
         | sym::simd_cttz => {
             intrinsic_args!(fx, args => (a); intrinsic);
 
@@ -367,6 +368,7 @@
                 (ty::Uint(_) | ty::Int(_), sym::simd_bswap) => fx.bcx.ins().bswap(lane),
                 (ty::Uint(_) | ty::Int(_), sym::simd_bitreverse) => fx.bcx.ins().bitrev(lane),
                 (ty::Uint(_) | ty::Int(_), sym::simd_ctlz) => fx.bcx.ins().clz(lane),
+                (ty::Uint(_) | ty::Int(_), sym::simd_ctpop) => fx.bcx.ins().popcnt(lane),
                 (ty::Uint(_) | ty::Int(_), sym::simd_cttz) => fx.bcx.ins().ctz(lane),
 
                 _ => unreachable!(),
@@ -974,7 +976,7 @@
             intrinsic_args!(fx, args => (ptr, offset); intrinsic);
 
             let (lane_count, ptr_lane_ty) = ptr.layout().ty.simd_size_and_type(fx.tcx);
-            let pointee_ty = ptr_lane_ty.builtin_deref(true).unwrap().ty;
+            let pointee_ty = ptr_lane_ty.builtin_deref(true).unwrap();
             let pointee_size = fx.layout_of(pointee_ty).size.bytes();
             let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
             let ret_lane_layout = fx.layout_of(ret_lane_ty);
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index c9f84b6..39bbad1 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -95,7 +95,7 @@
     pub(crate) use rustc_middle::mir::{self, *};
     pub(crate) use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
     pub(crate) use rustc_middle::ty::{
-        self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, TypeAndMut, UintTy,
+        self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, UintTy,
     };
     pub(crate) use rustc_span::Span;
     pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT};
@@ -331,9 +331,9 @@
                     sess.dcx().fatal(format!("can't compile for {}: {}", target_triple, err));
                 });
             if target_triple.architecture == target_lexicon::Architecture::X86_64 {
-                // Don't use "haswell" as the default, as it implies `has_lzcnt`.
-                // macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`.
-                builder.enable("nehalem").unwrap();
+                // Only set the target cpu on x86_64 as Cranelift is missing
+                // the target cpu list for most other targets.
+                builder.enable(sess.target.cpu.as_ref()).unwrap();
             }
             builder
         }
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index 1f20ec4..f9a7296 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -29,7 +29,7 @@
 
     if main_def_id.is_local() {
         let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx);
-        if !is_jit && module.get_name(tcx.symbol_name(instance).name).is_none() {
+        if module.get_name(tcx.symbol_name(instance).name).is_none() {
             return;
         }
     } else if !is_primary_cgu {
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index 7148580..fb18f45 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -179,6 +179,9 @@
             }
         }
         BinOp::Offset => unreachable!("Offset is not an integer operation"),
+        BinOp::AddWithOverflow | BinOp::SubWithOverflow | BinOp::MulWithOverflow => {
+            unreachable!("Overflow binops handled by `codegen_checked_int_binop`")
+        }
         // Compare binops handles by `codegen_binop`.
         BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge | BinOp::Cmp => {
             unreachable!("{:?}({:?}, {:?})", bin_op, in_lhs.layout().ty, in_rhs.layout().ty);
@@ -388,12 +391,8 @@
     in_lhs: CValue<'tcx>,
     in_rhs: CValue<'tcx>,
 ) -> CValue<'tcx> {
-    let is_thin_ptr = in_lhs
-        .layout()
-        .ty
-        .builtin_deref(true)
-        .map(|TypeAndMut { ty, mutbl: _ }| !has_ptr_meta(fx.tcx, ty))
-        .unwrap_or(true);
+    let is_thin_ptr =
+        in_lhs.layout().ty.builtin_deref(true).map(|ty| !has_ptr_meta(fx.tcx, ty)).unwrap_or(true);
 
     if is_thin_ptr {
         match bin_op {
@@ -404,7 +403,7 @@
                 codegen_compare_bin_op(fx, bin_op, false, lhs, rhs)
             }
             BinOp::Offset => {
-                let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap().ty;
+                let pointee_ty = in_lhs.layout().ty.builtin_deref(true).unwrap();
                 let (base, offset) = (in_lhs, in_rhs.load_scalar(fx));
                 let pointee_size = fx.layout_of(pointee_ty).size.bytes();
                 let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64);
diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs
index f33bacb..4acbc8a 100644
--- a/compiler/rustc_codegen_cranelift/src/unsize.rs
+++ b/compiler/rustc_codegen_cranelift/src/unsize.rs
@@ -127,7 +127,7 @@
     let dst_ty = dst.layout().ty;
     let mut coerce_ptr = || {
         let (base, info) =
-            if fx.layout_of(src.layout().ty.builtin_deref(true).unwrap().ty).is_unsized() {
+            if fx.layout_of(src.layout().ty.builtin_deref(true).unwrap()).is_unsized() {
                 let (old_base, old_info) = src.load_scalar_pair(fx);
                 unsize_ptr(fx, old_base, src.layout(), dst.layout(), Some(old_info))
             } else {
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index dded6df..4146137 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -317,14 +317,6 @@
 
         let clif_ty = fx.clif_type(layout.ty).unwrap();
 
-        if let ty::Bool = layout.ty.kind() {
-            assert!(
-                const_val == ty::ScalarInt::FALSE || const_val == ty::ScalarInt::TRUE,
-                "Invalid bool 0x{:032X}",
-                const_val
-            );
-        }
-
         let val = match layout.ty.kind() {
             ty::Uint(UintTy::U128) | ty::Int(IntTy::I128) => {
                 let const_val = const_val.assert_bits(layout.size);
@@ -819,7 +811,7 @@
     }
 
     pub(crate) fn place_deref(self, fx: &mut FunctionCx<'_, '_, 'tcx>) -> CPlace<'tcx> {
-        let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true).unwrap().ty);
+        let inner_layout = fx.layout_of(self.layout().ty.builtin_deref(true).unwrap());
         if has_ptr_meta(fx.tcx, inner_layout.ty) {
             let (addr, extra) = self.to_cvalue(fx).load_scalar_pair(fx);
             CPlace::for_ptr_with_extra(Pointer::new(addr), extra, inner_layout)
@@ -880,7 +872,7 @@
             let FnSig {
                 inputs_and_output: types_from,
                 c_variadic: c_variadic_from,
-                unsafety: unsafety_from,
+                safety: unsafety_from,
                 abi: abi_from,
             } = from_sig;
             let to_sig = fx
@@ -889,7 +881,7 @@
             let FnSig {
                 inputs_and_output: types_to,
                 c_variadic: c_variadic_to,
-                unsafety: unsafety_to,
+                safety: unsafety_to,
                 abi: abi_to,
             } = to_sig;
             let mut types_from = types_from.iter();
diff --git a/compiler/rustc_codegen_cranelift/src/vtable.rs b/compiler/rustc_codegen_cranelift/src/vtable.rs
index 04e2432..14c607c 100644
--- a/compiler/rustc_codegen_cranelift/src/vtable.rs
+++ b/compiler/rustc_codegen_cranelift/src/vtable.rs
@@ -59,7 +59,7 @@
 
         if let ty::Ref(_, ty, _) = arg.layout().ty.kind() {
             if ty.is_dyn_star() {
-                let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap().ty);
+                let inner_layout = fx.layout_of(arg.layout().ty.builtin_deref(true).unwrap());
                 let dyn_star = CPlace::for_ptr(Pointer::new(arg.load_scalar(fx)), inner_layout);
                 let ptr = dyn_star.place_field(fx, FieldIdx::ZERO).to_ptr();
                 let vtable =
diff --git a/compiler/rustc_codegen_cranelift/y.cmd b/compiler/rustc_codegen_cranelift/y.cmd
index e9b6886..4210684 100644
--- a/compiler/rustc_codegen_cranelift/y.cmd
+++ b/compiler/rustc_codegen_cranelift/y.cmd
@@ -1,8 +1,6 @@
 @echo off
 echo [BUILD] build system >&2
-mkdir build 2>nul
-rustc build_system/main.rs -o build\y.exe -Cdebuginfo=1 --edition 2021 || goto :error
-build\y.exe %* || goto :error
+cargo run --manifest-path build_system/Cargo.toml -- %* || goto :error
 goto :EOF
 
 :error
diff --git a/compiler/rustc_codegen_cranelift/y.ps1 b/compiler/rustc_codegen_cranelift/y.ps1
old mode 100644
new mode 100755
index 02ef0fc..821f0ec
--- a/compiler/rustc_codegen_cranelift/y.ps1
+++ b/compiler/rustc_codegen_cranelift/y.ps1
@@ -1,12 +1,7 @@
 $ErrorActionPreference = "Stop"
 
 $host.ui.WriteErrorLine("[BUILD] build system")
-New-Item -ItemType Directory -Force -Path build | Out-Null
-& rustc build_system/main.rs -o build\y.exe -Cdebuginfo=1 --edition 2021
-if ($LASTEXITCODE -ne 0) {
-    exit $LASTEXITCODE
-}
-& build\y.exe $args
+& cargo run --manifest-path build_system/Cargo.toml -- $args
 if ($LASTEXITCODE -ne 0) {
     exit $LASTEXITCODE
 }
diff --git a/compiler/rustc_codegen_cranelift/y.sh b/compiler/rustc_codegen_cranelift/y.sh
index bc925a2..b9152d2 100755
--- a/compiler/rustc_codegen_cranelift/y.sh
+++ b/compiler/rustc_codegen_cranelift/y.sh
@@ -2,5 +2,4 @@
 
 set -e
 echo "[BUILD] build system" 1>&2
-rustc build_system/main.rs -o y.bin -Cdebuginfo=1 --edition 2021
-exec ./y.bin "$@"
+exec cargo run --manifest-path build_system/Cargo.toml -- "$@"
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index 23a5e5f..4a3b6f6 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -1301,19 +1301,13 @@
     fn memmove(
         &mut self,
         dst: RValue<'gcc>,
-        dst_align: Align,
+        _dst_align: Align,
         src: RValue<'gcc>,
-        src_align: Align,
+        _src_align: Align,
         size: RValue<'gcc>,
         flags: MemFlags,
     ) {
-        if flags.contains(MemFlags::NONTEMPORAL) {
-            // HACK(nox): This is inefficient but there is no nontemporal memmove.
-            let val = self.load(src.get_type().get_pointee().expect("get_pointee"), src, src_align);
-            let ptr = self.pointercast(dst, self.type_ptr_to(self.val_ty(val)));
-            self.store_with_flags(val, ptr, dst_align, flags);
-            return;
-        }
+        assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memmove not supported");
         let size = self.intcast(size, self.type_size_t(), false);
         let _is_volatile = flags.contains(MemFlags::VOLATILE);
         let dst = self.pointercast(dst, self.type_i8p());
@@ -1335,6 +1329,7 @@
         _align: Align,
         flags: MemFlags,
     ) {
+        assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memset not supported");
         let _is_volatile = flags.contains(MemFlags::VOLATILE);
         let ptr = self.pointercast(ptr, self.type_i8p());
         let memset = self.context.get_builtin_function("memset");
diff --git a/compiler/rustc_codegen_gcc/src/debuginfo.rs b/compiler/rustc_codegen_gcc/src/debuginfo.rs
index aed1576..1d0a6d9 100644
--- a/compiler/rustc_codegen_gcc/src/debuginfo.rs
+++ b/compiler/rustc_codegen_gcc/src/debuginfo.rs
@@ -1,10 +1,9 @@
-use crate::rustc_index::Idx;
 use gccjit::{Location, RValue};
 use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
 use rustc_codegen_ssa::traits::{DebugInfoBuilderMethods, DebugInfoMethods};
 use rustc_data_structures::sync::Lrc;
 use rustc_index::bit_set::BitSet;
-use rustc_index::IndexVec;
+use rustc_index::{Idx, IndexVec};
 use rustc_middle::mir::{self, Body, SourceScope};
 use rustc_middle::ty::{Instance, PolyExistentialTraitRef, Ty};
 use rustc_session::config::DebugInfo;
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 451e525..43f12b5 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -670,11 +670,7 @@
                 let step3 = self.or(left, right);
 
                 // Fourth step.
-                if width == 8 {
-                    step3
-                } else {
-                    self.gcc_bswap(step3, width)
-                }
+                if width == 8 { step3 } else { self.gcc_bswap(step3, width) }
             }
             128 => {
                 // TODO(antoyo): find a more efficient implementation?
@@ -1225,7 +1221,7 @@
             iter::once(i8p),
             tcx.types.unit,
             false,
-            rustc_hir::Unsafety::Unsafe,
+            rustc_hir::Safety::Unsafe,
             Abi::Rust,
         )),
     );
@@ -1236,7 +1232,7 @@
             [i8p, i8p].iter().cloned(),
             tcx.types.unit,
             false,
-            rustc_hir::Unsafety::Unsafe,
+            rustc_hir::Safety::Unsafe,
             Abi::Rust,
         )),
     );
@@ -1245,7 +1241,7 @@
         [try_fn_ty, i8p, catch_fn_ty],
         tcx.types.i32,
         false,
-        rustc_hir::Unsafety::Unsafe,
+        rustc_hir::Safety::Unsafe,
         Abi::Rust,
     ));
     let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen);
diff --git a/compiler/rustc_codegen_gcc/src/type_of.rs b/compiler/rustc_codegen_gcc/src/type_of.rs
index 8f9bfbb..2155cab 100644
--- a/compiler/rustc_codegen_gcc/src/type_of.rs
+++ b/compiler/rustc_codegen_gcc/src/type_of.rs
@@ -1,15 +1,15 @@
 use std::fmt::Write;
 
-use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods};
 use gccjit::{Struct, Type};
+use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods};
 use rustc_middle::bug;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
 use rustc_target::abi::{
-    self, Abi, Align, FieldsShape, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface,
-    Variants, F128, F16, F32, F64,
+    self, Abi, Align, FieldsShape, Float, Int, Integer, PointeeInfo, Pointer, Size, TyAbiInterface,
+    Variants,
 };
 
 use crate::abi::{FnAbiGcc, FnAbiGccExt, GccType};
@@ -205,7 +205,7 @@
     /// of that field's type - this is useful for taking the address of
     /// that field and ensuring the struct has the right alignment.
     fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
-        use crate::rustc_middle::ty::layout::FnAbiOf;
+        use rustc_middle::ty::layout::FnAbiOf;
         // This must produce the same result for `repr(transparent)` wrappers as for the inner type!
         // In other words, this should generally not look at the type at all, but only at the
         // layout.
@@ -283,10 +283,7 @@
         match scalar.primitive() {
             Int(i, true) => cx.type_from_integer(i),
             Int(i, false) => cx.type_from_unsigned_integer(i),
-            F16 => cx.type_f16(),
-            F32 => cx.type_f32(),
-            F64 => cx.type_f64(),
-            F128 => cx.type_f128(),
+            Float(f) => cx.type_from_float(f),
             Pointer(address_space) => {
                 // If we know the alignment, pick something better than i8.
                 let pointee = if let Some(pointee) = self.pointee_info_at(cx, offset) {
diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs
index 123aef0..a6a3f0f 100644
--- a/compiler/rustc_codegen_llvm/src/abi.rs
+++ b/compiler/rustc_codegen_llvm/src/abi.rs
@@ -583,7 +583,7 @@
         let element_type_index = unsafe { llvm::LLVMRustGetElementTypeArgIndex(callsite) };
         if element_type_index >= 0 {
             let arg_ty = self.args[element_type_index as usize].layout.ty;
-            let pointee_ty = arg_ty.builtin_deref(true).expect("Must be pointer argument").ty;
+            let pointee_ty = arg_ty.builtin_deref(true).expect("Must be pointer argument");
             let element_type_attr = unsafe {
                 llvm::LLVMRustCreateElementTypeAttr(bx.llcx, bx.layout_of(pointee_ty).llvm_type(bx))
             };
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index e09869c..71d4343 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -904,8 +904,8 @@
         Primitive::Int(Integer::I16, _) => cx.type_i16(),
         Primitive::Int(Integer::I32, _) => cx.type_i32(),
         Primitive::Int(Integer::I64, _) => cx.type_i64(),
-        Primitive::F32 => cx.type_f32(),
-        Primitive::F64 => cx.type_f64(),
+        Primitive::Float(Float::F32) => cx.type_f32(),
+        Primitive::Float(Float::F64) => cx.type_f64(),
         // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
         Primitive::Pointer(_) => cx.type_from_integer(dl.ptr_sized_integer()),
         _ => unreachable!(),
@@ -950,7 +950,7 @@
             bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices))
         }
         (InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s))
-            if s.primitive() == Primitive::F64 =>
+            if s.primitive() == Primitive::Float(Float::F64) =>
         {
             bx.bitcast(value, bx.cx.type_i64())
         }
@@ -986,8 +986,8 @@
             match s.primitive() {
                 // MIPS only supports register-length arithmetics.
                 Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()),
-                Primitive::F32 => bx.bitcast(value, bx.cx.type_i32()),
-                Primitive::F64 => bx.bitcast(value, bx.cx.type_i64()),
+                Primitive::Float(Float::F32) => bx.bitcast(value, bx.cx.type_i32()),
+                Primitive::Float(Float::F64) => bx.bitcast(value, bx.cx.type_i64()),
                 _ => value,
             }
         }
@@ -1027,7 +1027,7 @@
             bx.shuffle_vector(value, bx.const_undef(vec_ty), bx.const_vector(&indices))
         }
         (InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s))
-            if s.primitive() == Primitive::F64 =>
+            if s.primitive() == Primitive::Float(Float::F64) =>
         {
             bx.bitcast(value, bx.cx.type_f64())
         }
@@ -1064,8 +1064,8 @@
                 // MIPS only supports register-length arithmetics.
                 Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()),
                 Primitive::Int(Integer::I16, _) => bx.trunc(value, bx.cx.type_i16()),
-                Primitive::F32 => bx.bitcast(value, bx.cx.type_f32()),
-                Primitive::F64 => bx.bitcast(value, bx.cx.type_f64()),
+                Primitive::Float(Float::F32) => bx.bitcast(value, bx.cx.type_f32()),
+                Primitive::Float(Float::F64) => bx.bitcast(value, bx.cx.type_f64()),
                 _ => value,
             }
         }
@@ -1100,7 +1100,7 @@
             cx.type_vector(elem_ty, count * 2)
         }
         (InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd), Abi::Scalar(s))
-            if s.primitive() == Primitive::F64 =>
+            if s.primitive() == Primitive::Float(Float::F64) =>
         {
             cx.type_i64()
         }
@@ -1136,8 +1136,8 @@
             match s.primitive() {
                 // MIPS only supports register-length arithmetics.
                 Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(),
-                Primitive::F32 => cx.type_i32(),
-                Primitive::F64 => cx.type_i64(),
+                Primitive::Float(Float::F32) => cx.type_i32(),
+                Primitive::Float(Float::F64) => cx.type_i64(),
                 _ => layout.llvm_type(cx),
             }
         }
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index d4a3e39..c304c0c 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -200,21 +200,20 @@
                 _ => panic!("unsupported arch {}", sess.target.arch),
             };
             let mut dlltool_cmd = std::process::Command::new(&dlltool);
-            dlltool_cmd.args([
-                "-d",
-                def_file_path.to_str().unwrap(),
-                "-D",
-                lib_name,
-                "-l",
-                output_path.to_str().unwrap(),
-                "-m",
-                dlltool_target_arch,
-                "-f",
-                dlltool_target_bitness,
-                "--no-leading-underscore",
-                "--temp-prefix",
-                temp_prefix.to_str().unwrap(),
-            ]);
+            dlltool_cmd
+                .arg("-d")
+                .arg(def_file_path)
+                .arg("-D")
+                .arg(lib_name)
+                .arg("-l")
+                .arg(&output_path)
+                .arg("-m")
+                .arg(dlltool_target_arch)
+                .arg("-f")
+                .arg(dlltool_target_bitness)
+                .arg("--no-leading-underscore")
+                .arg("--temp-prefix")
+                .arg(temp_prefix);
 
             match dlltool_cmd.output() {
                 Err(e) => {
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 1a1b4ae..230c58d 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -576,7 +576,7 @@
                         }
                     }
                 }
-                abi::F16 | abi::F32 | abi::F64 | abi::F128 => {}
+                abi::Float(_) => {}
             }
         }
 
@@ -976,6 +976,7 @@
         align: Align,
         flags: MemFlags,
     ) {
+        assert!(!flags.contains(MemFlags::NONTEMPORAL), "non-temporal memset not supported");
         let is_volatile = flags.contains(MemFlags::VOLATILE);
         unsafe {
             llvm::LLVMRustBuildMemSet(
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index c51a774..26ea95f 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -207,13 +207,8 @@
                 let cond_bitmap = coverage_context
                                     .try_get_mcdc_condition_bitmap(&instance, decision_depth)
                                     .expect("mcdc cond bitmap should have been allocated for merging into the global bitmap");
-                let bitmap_bytes = bx.tcx().coverage_ids_info(instance.def).mcdc_bitmap_bytes;
+                let bitmap_bytes = function_coverage_info.mcdc_bitmap_bytes;
                 assert!(bitmap_idx < bitmap_bytes, "bitmap index of the decision out of range");
-                assert!(
-                    bitmap_bytes <= function_coverage_info.mcdc_bitmap_bytes,
-                    "bitmap length disagreement: query says {bitmap_bytes} but function info only has {}",
-                    function_coverage_info.mcdc_bitmap_bytes
-                );
 
                 let fn_name = bx.get_pgo_func_name_var(instance);
                 let hash = bx.const_u64(function_coverage_info.function_source_hash);
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index e5fecdd..f44738b 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -1281,7 +1281,7 @@
         let mut names = generics
             .parent
             .map_or_else(Vec::new, |def_id| get_parameter_names(cx, cx.tcx.generics_of(def_id)));
-        names.extend(generics.params.iter().map(|param| param.name));
+        names.extend(generics.own_params.iter().map(|param| param.name));
         names
     }
 }
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
index 657e9ce..bacd74f 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
@@ -122,10 +122,7 @@
             // Niche tags are always normalized to unsized integers of the correct size.
             match tag.primitive() {
                 Primitive::Int(t, _) => t,
-                Primitive::F16 => Integer::I16,
-                Primitive::F32 => Integer::I32,
-                Primitive::F64 => Integer::I64,
-                Primitive::F128 => Integer::I128,
+                Primitive::Float(f) => Integer::from_size(f.size()).unwrap(),
                 // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
                 Primitive::Pointer(_) => {
                     // If the niche is the NULL value of a reference, then `discr_enum_ty` will be
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index 4fdaa59..6149c18 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -512,7 +512,7 @@
             let mut names = generics.parent.map_or_else(Vec::new, |def_id| {
                 get_parameter_names(cx, cx.tcx.generics_of(def_id))
             });
-            names.extend(generics.params.iter().map(|param| param.name));
+            names.extend(generics.own_params.iter().map(|param| param.name));
             names
         }
 
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 56550dbf..80e863a 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -18,7 +18,7 @@
 use rustc_middle::ty::{self, GenericArgsRef, Ty};
 use rustc_middle::{bug, span_bug};
 use rustc_span::{sym, Span, Symbol};
-use rustc_target::abi::{self, Align, HasDataLayout, Primitive, Size};
+use rustc_target::abi::{self, Align, Float, HasDataLayout, Primitive, Size};
 use rustc_target::spec::{HasTargetSpec, PanicStrategy};
 
 use std::cmp::Ordering;
@@ -231,13 +231,17 @@
                                     emit_va_arg(self, args[0], ret_ty)
                                 }
                             }
-                            Primitive::F16 => bug!("the va_arg intrinsic does not work with `f16`"),
-                            Primitive::F64 | Primitive::Pointer(_) => {
+                            Primitive::Float(Float::F16) => {
+                                bug!("the va_arg intrinsic does not work with `f16`")
+                            }
+                            Primitive::Float(Float::F64) | Primitive::Pointer(_) => {
                                 emit_va_arg(self, args[0], ret_ty)
                             }
                             // `va_arg` should never be used with the return type f32.
-                            Primitive::F32 => bug!("the va_arg intrinsic does not work with `f32`"),
-                            Primitive::F128 => {
+                            Primitive::Float(Float::F32) => {
+                                bug!("the va_arg intrinsic does not work with `f32`")
+                            }
+                            Primitive::Float(Float::F128) => {
                                 bug!("the va_arg intrinsic does not work with `f128`")
                             }
                         }
@@ -986,7 +990,7 @@
             [i8p],
             tcx.types.unit,
             false,
-            hir::Unsafety::Unsafe,
+            hir::Safety::Unsafe,
             Abi::Rust,
         )),
     );
@@ -997,7 +1001,7 @@
             [i8p, i8p],
             tcx.types.unit,
             false,
-            hir::Unsafety::Unsafe,
+            hir::Safety::Unsafe,
             Abi::Rust,
         )),
     );
@@ -1006,7 +1010,7 @@
         [try_fn_ty, i8p, catch_fn_ty],
         tcx.types.i32,
         false,
-        hir::Unsafety::Unsafe,
+        hir::Safety::Unsafe,
         Abi::Rust,
     ));
     let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen);
@@ -2332,7 +2336,10 @@
     }
 
     // Unary integer intrinsics
-    if matches!(name, sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctlz | sym::simd_cttz) {
+    if matches!(
+        name,
+        sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctlz | sym::simd_ctpop | sym::simd_cttz
+    ) {
         let vec_ty = bx.cx.type_vector(
             match *in_elem.kind() {
                 ty::Int(i) => bx.cx.type_int_from_ty(i),
@@ -2350,31 +2357,38 @@
             sym::simd_bswap => "bswap",
             sym::simd_bitreverse => "bitreverse",
             sym::simd_ctlz => "ctlz",
+            sym::simd_ctpop => "ctpop",
             sym::simd_cttz => "cttz",
             _ => unreachable!(),
         };
         let int_size = in_elem.int_size_and_signed(bx.tcx()).0.bits();
         let llvm_intrinsic = &format!("llvm.{}.v{}i{}", intrinsic_name, in_len, int_size,);
 
-        return if name == sym::simd_bswap && int_size == 8 {
+        return match name {
             // byte swap is no-op for i8/u8
-            Ok(args[0].immediate())
-        } else if matches!(name, sym::simd_ctlz | sym::simd_cttz) {
-            let fn_ty = bx.type_func(&[vec_ty, bx.type_i1()], vec_ty);
-            let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
-            Ok(bx.call(
-                fn_ty,
-                None,
-                None,
-                f,
-                &[args[0].immediate(), bx.const_int(bx.type_i1(), 0)],
-                None,
-                None,
-            ))
-        } else {
-            let fn_ty = bx.type_func(&[vec_ty], vec_ty);
-            let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
-            Ok(bx.call(fn_ty, None, None, f, &[args[0].immediate()], None, None))
+            sym::simd_bswap if int_size == 8 => Ok(args[0].immediate()),
+            sym::simd_ctlz | sym::simd_cttz => {
+                // for the (int, i1 immediate) pair, the second arg adds `(0, true) => poison`
+                let fn_ty = bx.type_func(&[vec_ty, bx.type_i1()], vec_ty);
+                let dont_poison_on_zero = bx.const_int(bx.type_i1(), 0);
+                let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
+                Ok(bx.call(
+                    fn_ty,
+                    None,
+                    None,
+                    f,
+                    &[args[0].immediate(), dont_poison_on_zero],
+                    None,
+                    None,
+                ))
+            }
+            sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctpop => {
+                // simple unary argument cases
+                let fn_ty = bx.type_func(&[vec_ty], vec_ty);
+                let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
+                Ok(bx.call(fn_ty, None, None, f, &[args[0].immediate()], None, None))
+            }
+            _ => unreachable!(),
         };
     }
 
@@ -2383,7 +2397,7 @@
         let pointee = in_elem.builtin_deref(true).unwrap_or_else(|| {
             span_bug!(span, "must be called with a vector of pointer types as first argument")
         });
-        let layout = bx.layout_of(pointee.ty);
+        let layout = bx.layout_of(pointee);
         let ptrs = args[0].immediate();
         // The second argument must be a ptr-sized integer.
         // (We don't care about the signedness, this is wrapping anyway.)
diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs
index 40ed6ba..5f60fd2 100644
--- a/compiler/rustc_codegen_llvm/src/type_of.rs
+++ b/compiler/rustc_codegen_llvm/src/type_of.rs
@@ -6,7 +6,7 @@
 use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 use rustc_target::abi::{Abi, Align, FieldsShape};
-use rustc_target::abi::{Int, Pointer, F128, F16, F32, F64};
+use rustc_target::abi::{Float, Int, Pointer};
 use rustc_target::abi::{Scalar, Size, Variants};
 
 use std::fmt::Write;
@@ -272,10 +272,7 @@
     fn scalar_llvm_type_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, scalar: Scalar) -> &'a Type {
         match scalar.primitive() {
             Int(i, _) => cx.type_from_integer(i),
-            F16 => cx.type_f16(),
-            F32 => cx.type_f32(),
-            F64 => cx.type_f64(),
-            F128 => cx.type_f128(),
+            Float(f) => cx.type_from_float(f),
             Pointer(address_space) => cx.type_ptr_ext(address_space),
         }
     }
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index f347a7f..3771fc6 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -6,8 +6,10 @@
 [dependencies]
 # tidy-alphabetical-start
 ar_archive_writer = "0.2.0"
+arrayvec = { version = "0.7", default-features = false }
 bitflags = "2.4.1"
 cc = "1.0.90"
+either = "1.5.0"
 itertools = "0.12"
 jobserver = "0.1.28"
 pathdiff = "0.2.0"
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 1f691d1..37b8f81 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -1230,7 +1230,10 @@
     if sanitizer.contains(SanitizerSet::DATAFLOW) {
         link_sanitizer_runtime(sess, flavor, linker, "dfsan");
     }
-    if sanitizer.contains(SanitizerSet::LEAK) {
+    if sanitizer.contains(SanitizerSet::LEAK)
+        && !sanitizer.contains(SanitizerSet::ADDRESS)
+        && !sanitizer.contains(SanitizerSet::HWADDRESS)
+    {
         link_sanitizer_runtime(sess, flavor, linker, "lsan");
     }
     if sanitizer.contains(SanitizerSet::MEMORY) {
@@ -3127,7 +3130,13 @@
 
     // 2. Implement the "linker flavor" part of this feature by asking `cc` to use some kind of
     // `lld` as the linker.
-    cmd.arg("-fuse-ld=lld");
+    //
+    // Note that wasm targets skip this step since the only option there anyway
+    // is to use LLD but the `wasm32-wasip2` target relies on a wrapper around
+    // this, `wasm-component-ld`, which is overridden if this option is passed.
+    if !sess.target.is_like_wasm {
+        cmd.arg("-fuse-ld=lld");
+    }
 
     if !flavor.is_gnu() {
         // Tell clang to use a non-default LLD flavor.
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index 358c24b..877e5b7 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -283,7 +283,7 @@
                 }
 
                 if src_f.layout.ty == dst_f.layout.ty {
-                    bx.typed_place_copy(dst_f, src_f);
+                    bx.typed_place_copy(dst_f.val, src_f.val, src_f.layout);
                 } else {
                     coerce_unsized_into(bx, src_f, dst_f);
                 }
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index c28b0d644..9bf055b 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -276,7 +276,7 @@
             sym::target_feature => {
                 if !tcx.is_closure_like(did.to_def_id())
                     && let Some(fn_sig) = fn_sig()
-                    && fn_sig.skip_binder().unsafety() == hir::Unsafety::Normal
+                    && fn_sig.skip_binder().safety() == hir::Safety::Safe
                 {
                     if tcx.sess.target.is_like_wasm || tcx.sess.opts.actually_rustdoc {
                         // The `#[target_feature]` attribute is allowed on
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index e9c7606..07473ee 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -365,7 +365,7 @@
                 }
                 output.push_str(" (*)(");
             } else {
-                output.push_str(sig.unsafety.prefix_str());
+                output.push_str(sig.safety.prefix_str());
 
                 if sig.abi != rustc_target::spec::abi::Abi::Rust {
                     output.push_str("extern \"");
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index 2f57695..ba6aad5 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -1060,7 +1060,7 @@
 
                         // Make sure that we've actually unwrapped the rcvr down
                         // to a pointer or ref to `dyn* Trait`.
-                        if !op.layout.ty.builtin_deref(true).unwrap().ty.is_dyn_star() {
+                        if !op.layout.ty.builtin_deref(true).unwrap().is_dyn_star() {
                             span_bug!(span, "can't codegen a virtual call on {:#?}", op);
                         }
                         let place = op.deref(bx.cx());
@@ -1454,9 +1454,9 @@
                         Some(pointee_align) => cmp::max(pointee_align, arg.layout.align.abi),
                         None => arg.layout.align.abi,
                     };
-                    let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align);
-                    op.val.store(bx, scratch);
-                    (scratch.val.llval, scratch.val.align, true)
+                    let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align);
+                    op.val.store(bx, scratch.with_type(arg.layout));
+                    (scratch.llval, scratch.align, true)
                 }
                 PassMode::Cast { .. } => {
                     let scratch = PlaceRef::alloca(bx, arg.layout);
@@ -1475,10 +1475,9 @@
                         // For `foo(packed.large_field)`, and types with <4 byte alignment on x86,
                         // alignment requirements may be higher than the type's alignment, so copy
                         // to a higher-aligned alloca.
-                        let scratch = PlaceRef::alloca_aligned(bx, arg.layout, required_align);
-                        let op_place = PlaceRef { val: op_place_val, layout: op.layout };
-                        bx.typed_place_copy(scratch, op_place);
-                        (scratch.val.llval, scratch.val.align, true)
+                        let scratch = PlaceValue::alloca(bx, arg.layout.size, required_align);
+                        bx.typed_place_copy(scratch, op_place_val, op.layout);
+                        (scratch.llval, scratch.align, true)
                     } else {
                         (op_place_val.llval, op_place_val.align, true)
                     }
@@ -1567,7 +1566,7 @@
             if place_val.llextra.is_some() {
                 bug!("closure arguments must be sized");
             }
-            let tuple_ptr = PlaceRef { val: place_val, layout: tuple.layout };
+            let tuple_ptr = place_val.with_type(tuple.layout);
             for i in 0..tuple.layout.fields.count() {
                 let field_ptr = tuple_ptr.project_field(bx, i);
                 let field = bx.load_operand(field_ptr);
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index 50bf1ef..6b89636 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -120,7 +120,7 @@
 {
     fn deref(&self, bx: &mut Bx) -> Self {
         bx.cx().layout_of(
-            self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)).ty,
+            self.ty.builtin_deref(true).unwrap_or_else(|| bug!("cannot deref `{}`", self.ty)),
         )
     }
 
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 2e00846..f88deaa 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -1,4 +1,4 @@
-use super::operand::{OperandRef, OperandValue};
+use super::operand::OperandRef;
 use super::place::PlaceRef;
 use super::FunctionCx;
 use crate::errors;
@@ -93,9 +93,10 @@
                 // into the (unoptimized) direct swapping implementation, so we disable it.
                 || bx.sess().target.arch == "spirv"
             {
-                let x_place = PlaceRef::new_sized(args[0].immediate(), pointee_layout);
-                let y_place = PlaceRef::new_sized(args[1].immediate(), pointee_layout);
-                bx.typed_place_swap(x_place, y_place);
+                let align = pointee_layout.align.abi;
+                let x_place = args[0].val.deref(align);
+                let y_place = args[1].val.deref(align);
+                bx.typed_place_swap(x_place, y_place, pointee_layout);
                 return Ok(());
             }
         }
@@ -113,15 +114,13 @@
             sym::va_end => bx.va_end(args[0].immediate()),
             sym::size_of_val => {
                 let tp_ty = fn_args.type_at(0);
-                let meta =
-                    if let OperandValue::Pair(_, meta) = args[0].val { Some(meta) } else { None };
+                let (_, meta) = args[0].val.pointer_parts();
                 let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
                 llsize
             }
             sym::min_align_of_val => {
                 let tp_ty = fn_args.type_at(0);
-                let meta =
-                    if let OperandValue::Pair(_, meta) = args[0].val { Some(meta) } else { None };
+                let (_, meta) = args[0].val.pointer_parts();
                 let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
                 llalign
             }
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index 38f77f2..32fd9b6 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -14,6 +14,9 @@
 
 use std::fmt;
 
+use arrayvec::ArrayVec;
+use either::Either;
+
 /// The representation of a Rust value. The enum variant is in fact
 /// uniquely determined by the value's type, but is kept as a
 /// safety check.
@@ -58,6 +61,70 @@
     ZeroSized,
 }
 
+impl<V: CodegenObject> OperandValue<V> {
+    /// If this is ZeroSized/Immediate/Pair, return an array of the 0/1/2 values.
+    /// If this is Ref, return the place.
+    #[inline]
+    pub fn immediates_or_place(self) -> Either<ArrayVec<V, 2>, PlaceValue<V>> {
+        match self {
+            OperandValue::ZeroSized => Either::Left(ArrayVec::new()),
+            OperandValue::Immediate(a) => Either::Left(ArrayVec::from_iter([a])),
+            OperandValue::Pair(a, b) => Either::Left([a, b].into()),
+            OperandValue::Ref(p) => Either::Right(p),
+        }
+    }
+
+    /// Given an array of 0/1/2 immediate values, return ZeroSized/Immediate/Pair.
+    #[inline]
+    pub fn from_immediates(immediates: ArrayVec<V, 2>) -> Self {
+        let mut it = immediates.into_iter();
+        let Some(a) = it.next() else {
+            return OperandValue::ZeroSized;
+        };
+        let Some(b) = it.next() else {
+            return OperandValue::Immediate(a);
+        };
+        OperandValue::Pair(a, b)
+    }
+
+    /// Treat this value as a pointer and return the data pointer and
+    /// optional metadata as backend values.
+    ///
+    /// If you're making a place, use [`Self::deref`] instead.
+    pub fn pointer_parts(self) -> (V, Option<V>) {
+        match self {
+            OperandValue::Immediate(llptr) => (llptr, None),
+            OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
+            _ => bug!("OperandValue cannot be a pointer: {self:?}"),
+        }
+    }
+
+    /// Treat this value as a pointer and return the place to which it points.
+    ///
+    /// The pointer immediate doesn't inherently know its alignment,
+    /// so you need to pass it in. If you want to get it from a type's ABI
+    /// alignment, then maybe you want [`OperandRef::deref`] instead.
+    ///
+    /// This is the inverse of [`PlaceValue::address`].
+    pub fn deref(self, align: Align) -> PlaceValue<V> {
+        let (llval, llextra) = self.pointer_parts();
+        PlaceValue { llval, llextra, align }
+    }
+
+    pub(crate) fn is_expected_variant_for_type<'tcx, Cx: LayoutTypeMethods<'tcx>>(
+        &self,
+        cx: &Cx,
+        ty: TyAndLayout<'tcx>,
+    ) -> bool {
+        match self {
+            OperandValue::ZeroSized => ty.is_zst(),
+            OperandValue::Immediate(_) => cx.is_backend_immediate(ty),
+            OperandValue::Pair(_, _) => cx.is_backend_scalar_pair(ty),
+            OperandValue::Ref(_) => cx.is_backend_ref(ty),
+        }
+    }
+}
+
 /// An `OperandRef` is an "SSA" reference to a Rust value, along with
 /// its type.
 ///
@@ -205,6 +272,15 @@
         }
     }
 
+    /// Asserts that this operand is a pointer (or reference) and returns
+    /// the place to which it points.  (This requires no code to be emitted
+    /// as we represent places using the pointer to the place.)
+    ///
+    /// This uses [`Ty::builtin_deref`] to include the type of the place and
+    /// assumes the place is aligned to the pointee's usual ABI alignment.
+    ///
+    /// If you don't need the type, see [`OperandValue::pointer_parts`]
+    /// or [`OperandValue::deref`].
     pub fn deref<Cx: LayoutTypeMethods<'tcx>>(self, cx: &Cx) -> PlaceRef<'tcx, V> {
         if self.layout.ty.is_box() {
             // Derefer should have removed all Box derefs
@@ -215,18 +291,10 @@
             .layout
             .ty
             .builtin_deref(true)
-            .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self))
-            .ty;
+            .unwrap_or_else(|| bug!("deref of non-pointer {:?}", self));
 
-        let (llptr, llextra) = match self.val {
-            OperandValue::Immediate(llptr) => (llptr, None),
-            OperandValue::Pair(llptr, llextra) => (llptr, Some(llextra)),
-            OperandValue::Ref(..) => bug!("Deref of by-Ref operand {:?}", self),
-            OperandValue::ZeroSized => bug!("Deref of ZST operand {:?}", self),
-        };
         let layout = cx.layout_of(projected_ty);
-        let val = PlaceValue { llval: llptr, llextra, align: layout.align.abi };
-        PlaceRef { val, layout }
+        self.val.deref(layout.align.abi).with_type(layout)
     }
 
     /// If this operand is a `Pair`, we return an aggregate with the two values.
@@ -419,8 +487,7 @@
                 if val.llextra.is_some() {
                     bug!("cannot directly store unsized values");
                 }
-                let source_place = PlaceRef { val, layout: dest.layout };
-                bx.typed_place_copy_with_flags(dest, source_place, flags);
+                bx.typed_place_copy_with_flags(dest.val, val, dest.layout, flags);
             }
             OperandValue::Immediate(s) => {
                 let val = bx.from_immediate(s);
@@ -455,8 +522,7 @@
             .layout
             .ty
             .builtin_deref(true)
-            .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest))
-            .ty;
+            .unwrap_or_else(|| bug!("indirect_dest has non-pointer type: {:?}", indirect_dest));
 
         let OperandValue::Ref(PlaceValue { llval: llptr, llextra: Some(llextra), .. }) = self
         else {
diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs
index 870a105..971ac2d 100644
--- a/compiler/rustc_codegen_ssa/src/mir/place.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/place.rs
@@ -10,12 +10,15 @@
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, Ty};
-use rustc_target::abi::{Align, FieldsShape, Int, Pointer, TagEncoding};
+use rustc_target::abi::{Align, FieldsShape, Int, Pointer, Size, TagEncoding};
 use rustc_target::abi::{VariantIdx, Variants};
 
 /// The location and extra runtime properties of the place.
 ///
 /// Typically found in a [`PlaceRef`] or an [`OperandValue::Ref`].
+///
+/// As a location in memory, this has no specific type. If you want to
+/// load or store it using a typed operation, use [`Self::with_type`].
 #[derive(Copy, Clone, Debug)]
 pub struct PlaceValue<V> {
     /// A pointer to the contents of the place.
@@ -35,6 +38,41 @@
     pub fn new_sized(llval: V, align: Align) -> PlaceValue<V> {
         PlaceValue { llval, llextra: None, align }
     }
+
+    /// Allocates a stack slot in the function for a value
+    /// of the specified size and alignment.
+    ///
+    /// The allocation itself is untyped.
+    pub fn alloca<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx, Value = V>>(
+        bx: &mut Bx,
+        size: Size,
+        align: Align,
+    ) -> PlaceValue<V> {
+        let llval = bx.alloca(size, align);
+        PlaceValue::new_sized(llval, align)
+    }
+
+    /// Creates a `PlaceRef` to this location with the given type.
+    pub fn with_type<'tcx>(self, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
+        debug_assert!(
+            layout.is_unsized() || layout.abi.is_uninhabited() || self.llextra.is_none(),
+            "Had pointer metadata {:?} for sized type {layout:?}",
+            self.llextra,
+        );
+        PlaceRef { val: self, layout }
+    }
+
+    /// Gets the pointer to this place as an [`OperandValue::Immediate`]
+    /// or, for those needing metadata, an [`OperandValue::Pair`].
+    ///
+    /// This is the inverse of [`OperandValue::deref`].
+    pub fn address(self) -> OperandValue<V> {
+        if let Some(llextra) = self.llextra {
+            OperandValue::Pair(self.llval, llextra)
+        } else {
+            OperandValue::Immediate(self.llval)
+        }
+    }
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -52,9 +90,7 @@
 
 impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> {
     pub fn new_sized(llval: V, layout: TyAndLayout<'tcx>) -> PlaceRef<'tcx, V> {
-        assert!(layout.is_sized());
-        let val = PlaceValue::new_sized(llval, layout.align.abi);
-        PlaceRef { val, layout }
+        PlaceRef::new_sized_aligned(llval, layout, layout.align.abi)
     }
 
     pub fn new_sized_aligned(
@@ -63,8 +99,7 @@
         align: Align,
     ) -> PlaceRef<'tcx, V> {
         assert!(layout.is_sized());
-        let val = PlaceValue::new_sized(llval, align);
-        PlaceRef { val, layout }
+        PlaceValue::new_sized(llval, align).with_type(layout)
     }
 
     // FIXME(eddyb) pass something else for the name so no work is done
@@ -73,17 +108,8 @@
         bx: &mut Bx,
         layout: TyAndLayout<'tcx>,
     ) -> Self {
-        Self::alloca_aligned(bx, layout, layout.align.abi)
-    }
-
-    pub fn alloca_aligned<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
-        bx: &mut Bx,
-        layout: TyAndLayout<'tcx>,
-        align: Align,
-    ) -> Self {
         assert!(layout.is_sized(), "tried to statically allocate unsized place");
-        let tmp = bx.alloca(layout.size, align);
-        Self::new_sized_aligned(tmp, layout, align)
+        PlaceValue::alloca(bx, layout.size, layout.align.abi).with_type(layout)
     }
 
     /// Returns a place for an indirect reference to an unsized place.
@@ -132,18 +158,12 @@
             } else {
                 bx.inbounds_ptradd(self.val.llval, bx.const_usize(offset.bytes()))
             };
-            PlaceRef {
-                val: PlaceValue {
+            let val = PlaceValue {
                     llval,
-                    llextra: if bx.cx().type_has_metadata(field.ty) {
-                        self.val.llextra
-                    } else {
-                        None
-                    },
+                llextra: if bx.cx().type_has_metadata(field.ty) { self.val.llextra } else { None },
                     align: effective_field_align,
-                },
-                layout: field,
-            }
+            };
+            val.with_type(field)
         };
 
         // Simple cases, which don't need DST adjustment:
@@ -198,7 +218,7 @@
         let ptr = bx.inbounds_ptradd(self.val.llval, offset);
         let val =
             PlaceValue { llval: ptr, llextra: self.val.llextra, align: effective_field_align };
-        PlaceRef { val, layout: field }
+        val.with_type(field)
     }
 
     /// Obtain the actual discriminant of a value.
@@ -387,18 +407,13 @@
             layout.size
         };
 
-        PlaceRef {
-            val: PlaceValue {
-                llval: bx.inbounds_gep(
+        let llval = bx.inbounds_gep(
                     bx.cx().backend_type(self.layout),
                     self.val.llval,
                     &[bx.cx().const_usize(0), llindex],
-                ),
-                llextra: None,
-                align: self.val.align.restrict_for_offset(offset),
-            },
-            layout,
-        }
+        );
+        let align = self.val.align.restrict_for_offset(offset);
+        PlaceValue::new_sized(llval, align).with_type(layout)
     }
 
     pub fn project_downcast<Bx: BuilderMethods<'a, 'tcx, Value = V>>(
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index 4e7d251..00b28cb 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -8,14 +8,16 @@
 use crate::MemFlags;
 
 use rustc_hir as hir;
-use rustc_middle::mir::{self, AggregateKind, Operand};
+use rustc_middle::mir;
 use rustc_middle::ty::cast::{CastTy, IntTy};
 use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, adjustment::PointerCoercion, Instance, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::OptLevel;
 use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi::{self, FIRST_VARIANT};
+use rustc_target::abi::{self, FieldIdx, FIRST_VARIANT};
+
+use arrayvec::ArrayVec;
 
 impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
     #[instrument(level = "trace", skip(self, bx))]
@@ -72,8 +74,7 @@
                         if val.llextra.is_some() {
                             bug!("unsized coercion on an unsized rvalue");
                         }
-                        let source = PlaceRef { val, layout: operand.layout };
-                        base::coerce_unsized_into(bx, source, dest);
+                        base::coerce_unsized_into(bx, val.with_type(operand.layout), dest);
                     }
                     OperandValue::ZeroSized => {
                         bug!("unsized coercion on a ZST rvalue");
@@ -120,7 +121,11 @@
                 bx.write_operand_repeatedly(cg_elem, count, dest);
             }
 
-            mir::Rvalue::Aggregate(ref kind, ref operands) => {
+            // This implementation does field projection, so never use it for `RawPtr`,
+            // which will always be fine with the `codegen_rvalue_operand` path below.
+            mir::Rvalue::Aggregate(ref kind, ref operands)
+                if !matches!(**kind, mir::AggregateKind::RawPtr(..)) =>
+            {
                 let (variant_index, variant_dest, active_field_index) = match **kind {
                     mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => {
                         let variant_dest = dest.project_downcast(bx, variant_index);
@@ -182,10 +187,7 @@
             OperandValue::Immediate(..) | OperandValue::Pair(..) => {
                 // When we have immediate(s), the alignment of the source is irrelevant,
                 // so we can store them using the destination's alignment.
-                src.val.store(
-                    bx,
-                    PlaceRef::new_sized_aligned(dst.val.llval, src.layout, dst.val.align),
-                );
+                src.val.store(bx, dst.val.with_type(src.layout));
             }
         }
     }
@@ -223,8 +225,7 @@
             OperandValue::Ref(source_place_val) => {
                 debug_assert_eq!(source_place_val.llextra, None);
                 debug_assert!(matches!(operand_kind, OperandValueKind::Ref));
-                let fake_place = PlaceRef { val: source_place_val, layout: cast };
-                Some(bx.load_operand(fake_place).val)
+                Some(bx.load_operand(source_place_val.with_type(cast)).val)
             }
             OperandValue::ZeroSized => {
                 let OperandValueKind::ZeroSized = operand_kind else {
@@ -306,17 +307,15 @@
         self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
 
         imm = match (from_scalar.primitive(), to_scalar.primitive()) {
-            (Int(..) | F16 | F32 | F64 | F128, Int(..) | F16 | F32 | F64 | F128) => {
-                bx.bitcast(imm, to_backend_ty)
-            }
+            (Int(..) | Float(_), Int(..) | Float(_)) => bx.bitcast(imm, to_backend_ty),
             (Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
             (Int(..), Pointer(..)) => bx.ptradd(bx.const_null(bx.type_ptr()), imm),
             (Pointer(..), Int(..)) => bx.ptrtoint(imm, to_backend_ty),
-            (F16 | F32 | F64 | F128, Pointer(..)) => {
+            (Float(_), Pointer(..)) => {
                 let int_imm = bx.bitcast(imm, bx.cx().type_isize());
                 bx.ptradd(bx.const_null(bx.type_ptr()), int_imm)
             }
-            (Pointer(..), F16 | F32 | F64 | F128) => {
+            (Pointer(..), Float(_)) => {
                 let int_imm = bx.ptrtoint(imm, bx.cx().type_isize());
                 bx.bitcast(int_imm, to_backend_ty)
             }
@@ -452,23 +451,7 @@
                     }
                     mir::CastKind::PointerCoercion(PointerCoercion::Unsize) => {
                         assert!(bx.cx().is_backend_scalar_pair(cast));
-                        let (lldata, llextra) = match operand.val {
-                            OperandValue::Pair(lldata, llextra) => {
-                                // unsize from a fat pointer -- this is a
-                                // "trait-object-to-supertrait" coercion.
-                                (lldata, Some(llextra))
-                            }
-                            OperandValue::Immediate(lldata) => {
-                                // "standard" unsize
-                                (lldata, None)
-                            }
-                            OperandValue::Ref(..) => {
-                                bug!("by-ref operand {:?} in `codegen_rvalue_operand`", operand);
-                            }
-                            OperandValue::ZeroSized => {
-                                bug!("zero-sized operand {:?} in `codegen_rvalue_operand`", operand);
-                            }
-                        };
+                        let (lldata, llextra) = operand.val.pointer_parts();
                         let (lldata, llextra) =
                             base::unsize_ptr(bx, lldata, operand.layout.ty, cast.ty, llextra);
                         OperandValue::Pair(lldata, llextra)
@@ -489,12 +472,7 @@
                         }
                     }
                     mir::CastKind::DynStar => {
-                        let (lldata, llextra) = match operand.val {
-                            OperandValue::Ref(..) => todo!(),
-                            OperandValue::Immediate(v) => (v, None),
-                            OperandValue::Pair(v, l) => (v, Some(l)),
-                            OperandValue::ZeroSized => bug!("ZST -- which is not PointerLike -- in DynStar"),
-                        };
+                        let (lldata, llextra) = operand.val.pointer_parts();
                         let (lldata, llextra) =
                             base::cast_to_dyn_star(bx, lldata, operand.layout, cast.ty, llextra);
                         OperandValue::Pair(lldata, llextra)
@@ -581,7 +559,9 @@
                 self.codegen_place_to_pointer(bx, place, mk_ref)
             }
 
-            mir::Rvalue::CopyForDeref(place) => self.codegen_operand(bx, &Operand::Copy(place)),
+            mir::Rvalue::CopyForDeref(place) => {
+                self.codegen_operand(bx, &mir::Operand::Copy(place))
+            }
             mir::Rvalue::AddressOf(mutability, place) => {
                 let mk_ptr =
                     move |tcx: TyCtxt<'tcx>, ty: Ty<'tcx>| Ty::new_ptr(tcx, ty, mutability);
@@ -596,6 +576,22 @@
                 }
             }
 
+            mir::Rvalue::BinaryOp(op_with_overflow, box (ref lhs, ref rhs))
+                if let Some(op) = op_with_overflow.overflowing_to_wrapping() =>
+            {
+                let lhs = self.codegen_operand(bx, lhs);
+                let rhs = self.codegen_operand(bx, rhs);
+                let result = self.codegen_scalar_checked_binop(
+                    bx,
+                    op,
+                    lhs.immediate(),
+                    rhs.immediate(),
+                    lhs.layout.ty,
+                );
+                let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty);
+                let operand_ty = Ty::new_tup(bx.tcx(), &[val_ty, bx.tcx().types.bool]);
+                OperandRef { val: result, layout: bx.cx().layout_of(operand_ty) }
+            }
             mir::Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => {
                 let lhs = self.codegen_operand(bx, lhs);
                 let rhs = self.codegen_operand(bx, rhs);
@@ -624,20 +620,6 @@
                     layout: bx.cx().layout_of(op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty)),
                 }
             }
-            mir::Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => {
-                let lhs = self.codegen_operand(bx, lhs);
-                let rhs = self.codegen_operand(bx, rhs);
-                let result = self.codegen_scalar_checked_binop(
-                    bx,
-                    op,
-                    lhs.immediate(),
-                    rhs.immediate(),
-                    lhs.layout.ty,
-                );
-                let val_ty = op.ty(bx.tcx(), lhs.layout.ty, rhs.layout.ty);
-                let operand_ty = Ty::new_tup(bx.tcx(), &[val_ty, bx.tcx().types.bool]);
-                OperandRef { val: result, layout: bx.cx().layout_of(operand_ty) }
-            }
 
             mir::Rvalue::UnaryOp(op, ref operand) => {
                 let operand = self.codegen_operand(bx, operand);
@@ -720,29 +702,45 @@
                 OperandRef { val: OperandValue::Immediate(static_), layout }
             }
             mir::Rvalue::Use(ref operand) => self.codegen_operand(bx, operand),
-            mir::Rvalue::Aggregate(box mir::AggregateKind::RawPtr(..), ref fields) => {
+            mir::Rvalue::Repeat(..) => bug!("{rvalue:?} in codegen_rvalue_operand"),
+            mir::Rvalue::Aggregate(_, ref fields) => {
                 let ty = rvalue.ty(self.mir, self.cx.tcx());
-                let layout = self.cx.layout_of(self.monomorphize(ty));
-                let [data, meta] = &*fields.raw else {
-                    bug!("RawPtr fields: {fields:?}");
-                };
-                let data = self.codegen_operand(bx, data);
-                let meta = self.codegen_operand(bx, meta);
-                match (data.val, meta.val) {
-                    (p @ OperandValue::Immediate(_), OperandValue::ZeroSized) => {
-                        OperandRef { val: p, layout }
-                    }
-                    (OperandValue::Immediate(p), OperandValue::Immediate(m)) => {
-                        OperandRef { val: OperandValue::Pair(p, m), layout }
-                    }
-                    _ => bug!("RawPtr operands {data:?} {meta:?}"),
+                let ty = self.monomorphize(ty);
+                let layout = self.cx.layout_of(ty);
+
+                // `rvalue_creates_operand` has arranged that we only get here if
+                // we can build the aggregate immediate from the field immediates.
+                let mut inputs = ArrayVec::<Bx::Value, 2>::new();
+                let mut input_scalars = ArrayVec::<abi::Scalar, 2>::new();
+                for field_idx in layout.fields.index_by_increasing_offset() {
+                    let field_idx = FieldIdx::from_usize(field_idx);
+                    let op = self.codegen_operand(bx, &fields[field_idx]);
+                    let values = op.val.immediates_or_place().left_or_else(|p| {
+                        bug!("Field {field_idx:?} is {p:?} making {layout:?}");
+                    });
+                    inputs.extend(values);
+                    let scalars = self.value_kind(op.layout).scalars().unwrap();
+                    input_scalars.extend(scalars);
                 }
-            }
-            mir::Rvalue::Repeat(..) | mir::Rvalue::Aggregate(..) => {
-                // According to `rvalue_creates_operand`, only ZST
-                // aggregate rvalues are allowed to be operands.
-                let ty = rvalue.ty(self.mir, self.cx.tcx());
-                OperandRef::zero_sized(self.cx.layout_of(self.monomorphize(ty)))
+
+                let output_scalars = self.value_kind(layout).scalars().unwrap();
+                itertools::izip!(&mut inputs, input_scalars, output_scalars).for_each(
+                    |(v, in_s, out_s)| {
+                        if in_s != out_s {
+                            // We have to be really careful about bool here, because
+                            // `(bool,)` stays i1 but `Cell<bool>` becomes i8.
+                            *v = bx.from_immediate(*v);
+                            *v = bx.to_immediate_scalar(*v, out_s);
+                        }
+                    },
+                );
+
+                let val = OperandValue::from_immediates(inputs);
+                debug_assert!(
+                    val.is_expected_variant_for_type(self.cx, layout),
+                    "Made wrong variant {val:?} for type {layout:?}",
+                );
+                OperandRef { val, layout }
             }
             mir::Rvalue::ShallowInitBox(ref operand, content_ty) => {
                 let operand = self.codegen_operand(bx, operand);
@@ -780,16 +778,18 @@
         mk_ptr_ty: impl FnOnce(TyCtxt<'tcx>, Ty<'tcx>) -> Ty<'tcx>,
     ) -> OperandRef<'tcx, Bx::Value> {
         let cg_place = self.codegen_place(bx, place.as_ref());
+        let val = cg_place.val.address();
 
         let ty = cg_place.layout.ty;
+        debug_assert!(
+            if bx.cx().type_has_metadata(ty) {
+                matches!(val, OperandValue::Pair(..))
+            } else {
+                matches!(val, OperandValue::Immediate(..))
+            },
+            "Address of place was unexpectedly {val:?} for pointee type {ty:?}",
+        );
 
-        // Note: places are indirect, so storing the `llval` into the
-        // destination effectively creates a reference.
-        let val = if !bx.cx().type_has_metadata(ty) {
-            OperandValue::Immediate(cg_place.val.llval)
-        } else {
-            OperandValue::Pair(cg_place.val.llval, cg_place.val.llextra.unwrap())
-        };
         OperandRef { val, layout: self.cx.layout_of(mk_ptr_ty(self.cx.tcx(), ty)) }
     }
 
@@ -870,8 +870,7 @@
             mir::BinOp::Offset => {
                 let pointee_type = input_ty
                     .builtin_deref(true)
-                    .unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty))
-                    .ty;
+                    .unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty));
                 let pointee_layout = bx.cx().layout_of(pointee_type);
                 if pointee_layout.is_zst() {
                     // `Offset` works in terms of the size of pointee,
@@ -931,6 +930,11 @@
                     bx.select(is_lt, bx.cx().const_i8(Ordering::Less as i8), ge)
                 }
             }
+            mir::BinOp::AddWithOverflow
+            | mir::BinOp::SubWithOverflow
+            | mir::BinOp::MulWithOverflow => {
+                bug!("{op:?} needs to return a pair, so call codegen_scalar_checked_binop instead")
+            }
         }
     }
 
@@ -1043,21 +1047,35 @@
             mir::Rvalue::Cast(..) | // (*)
             mir::Rvalue::ShallowInitBox(..) | // (*)
             mir::Rvalue::BinaryOp(..) |
-            mir::Rvalue::CheckedBinaryOp(..) |
             mir::Rvalue::UnaryOp(..) |
             mir::Rvalue::Discriminant(..) |
             mir::Rvalue::NullaryOp(..) |
             mir::Rvalue::ThreadLocalRef(_) |
             mir::Rvalue::Use(..) => // (*)
                 true,
-            // This always produces a `ty::RawPtr`, so will be Immediate or Pair
-            mir::Rvalue::Aggregate(box AggregateKind::RawPtr(..), ..) => true,
-            mir::Rvalue::Repeat(..) |
-            mir::Rvalue::Aggregate(..) => {
+            // Arrays are always aggregates, so it's not worth checking anything here.
+            // (If it's really `[(); N]` or `[T; 0]` and we use the place path, fine.)
+            mir::Rvalue::Repeat(..) => false,
+            mir::Rvalue::Aggregate(ref kind, _) => {
+                let allowed_kind = match **kind {
+                    // This always produces a `ty::RawPtr`, so will be Immediate or Pair
+                    mir::AggregateKind::RawPtr(..) => true,
+                    mir::AggregateKind::Array(..) => false,
+                    mir::AggregateKind::Tuple => true,
+                    mir::AggregateKind::Adt(def_id, ..) => {
+                        let adt_def = self.cx.tcx().adt_def(def_id);
+                        adt_def.is_struct() && !adt_def.repr().simd()
+                    }
+                    mir::AggregateKind::Closure(..) => true,
+                    // FIXME: Can we do this for simple coroutines too?
+                    mir::AggregateKind::Coroutine(..) | mir::AggregateKind::CoroutineClosure(..) => false,
+                };
+                allowed_kind && {
                 let ty = rvalue.ty(self.mir, self.cx.tcx());
                 let ty = self.monomorphize(ty);
-                // For ZST this can be `OperandValueKind::ZeroSized`.
-                self.cx.spanned_layout_of(ty, span).is_zst()
+                    let layout = self.cx.spanned_layout_of(ty, span);
+                    !self.cx.is_backend_ref(layout)
+                }
             }
         }
 
@@ -1099,3 +1117,14 @@
     Pair(abi::Scalar, abi::Scalar),
     ZeroSized,
 }
+
+impl OperandValueKind {
+    fn scalars(self) -> Option<ArrayVec<abi::Scalar, 2>> {
+        Some(match self {
+            OperandValueKind::ZeroSized => ArrayVec::new(),
+            OperandValueKind::Immediate(a) => ArrayVec::from_iter([a]),
+            OperandValueKind::Pair(a, b) => [a, b].into(),
+            OperandValueKind::Ref => return None,
+        })
+    }
+}
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 51b22bf..9fd6eb8 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -186,6 +186,15 @@
         align: Align,
         flags: MemFlags,
     ) -> Self::Value;
+    fn store_to_place_with_flags(
+        &mut self,
+        val: Self::Value,
+        place: PlaceValue<Self::Value>,
+        flags: MemFlags,
+    ) -> Self::Value {
+        debug_assert_eq!(place.llextra, None);
+        self.store_with_flags(val, place.llval, place.align, flags)
+    }
     fn atomic_store(
         &mut self,
         val: Self::Value,
@@ -238,7 +247,10 @@
         } else {
             (in_ty, dest_ty)
         };
-        assert!(matches!(self.cx().type_kind(float_ty), TypeKind::Float | TypeKind::Double));
+        assert!(matches!(
+            self.cx().type_kind(float_ty),
+            TypeKind::Half | TypeKind::Float | TypeKind::Double | TypeKind::FP128
+        ));
         assert_eq!(self.cx().type_kind(int_ty), TypeKind::Integer);
 
         if let Some(false) = self.cx().sess().opts.unstable_opts.saturating_float_casts {
@@ -286,35 +298,36 @@
     /// (For example, typed load-stores with alias metadata.)
     fn typed_place_copy(
         &mut self,
-        dst: PlaceRef<'tcx, Self::Value>,
-        src: PlaceRef<'tcx, Self::Value>,
+        dst: PlaceValue<Self::Value>,
+        src: PlaceValue<Self::Value>,
+        layout: TyAndLayout<'tcx>,
     ) {
-        self.typed_place_copy_with_flags(dst, src, MemFlags::empty());
+        self.typed_place_copy_with_flags(dst, src, layout, MemFlags::empty());
     }
 
     fn typed_place_copy_with_flags(
         &mut self,
-        dst: PlaceRef<'tcx, Self::Value>,
-        src: PlaceRef<'tcx, Self::Value>,
+        dst: PlaceValue<Self::Value>,
+        src: PlaceValue<Self::Value>,
+        layout: TyAndLayout<'tcx>,
         flags: MemFlags,
     ) {
-        debug_assert!(src.val.llextra.is_none(), "cannot directly copy from unsized values");
-        debug_assert!(dst.val.llextra.is_none(), "cannot directly copy into unsized values");
-        debug_assert_eq!(dst.layout.size, src.layout.size);
+        debug_assert!(layout.is_sized(), "cannot typed-copy an unsigned type");
+        debug_assert!(src.llextra.is_none(), "cannot directly copy from unsized values");
+        debug_assert!(dst.llextra.is_none(), "cannot directly copy into unsized values");
         if flags.contains(MemFlags::NONTEMPORAL) {
             // HACK(nox): This is inefficient but there is no nontemporal memcpy.
-            let ty = self.backend_type(dst.layout);
-            let val = self.load_from_place(ty, src.val);
-            self.store_with_flags(val, dst.val.llval, dst.val.align, flags);
-        } else if self.sess().opts.optimize == OptLevel::No && self.is_backend_immediate(dst.layout)
-        {
+            let ty = self.backend_type(layout);
+            let val = self.load_from_place(ty, src);
+            self.store_to_place_with_flags(val, dst, flags);
+        } else if self.sess().opts.optimize == OptLevel::No && self.is_backend_immediate(layout) {
             // If we're not optimizing, the aliasing information from `memcpy`
             // isn't useful, so just load-store the value for smaller code.
-            let temp = self.load_operand(src);
-            temp.val.store_with_flags(self, dst, flags);
-        } else if !dst.layout.is_zst() {
-            let bytes = self.const_usize(dst.layout.size.bytes());
-            self.memcpy(dst.val.llval, dst.val.align, src.val.llval, src.val.align, bytes, flags);
+            let temp = self.load_operand(src.with_type(layout));
+            temp.val.store_with_flags(self, dst.with_type(layout), flags);
+        } else if !layout.is_zst() {
+            let bytes = self.const_usize(layout.size.bytes());
+            self.memcpy(dst.llval, dst.align, src.llval, src.align, bytes, flags);
         }
     }
 
@@ -327,18 +340,19 @@
     /// cases (in non-debug), preferring the fallback body instead.
     fn typed_place_swap(
         &mut self,
-        left: PlaceRef<'tcx, Self::Value>,
-        right: PlaceRef<'tcx, Self::Value>,
+        left: PlaceValue<Self::Value>,
+        right: PlaceValue<Self::Value>,
+        layout: TyAndLayout<'tcx>,
     ) {
-        let mut temp = self.load_operand(left);
+        let mut temp = self.load_operand(left.with_type(layout));
         if let OperandValue::Ref(..) = temp.val {
             // The SSA value isn't stand-alone, so we need to copy it elsewhere
-            let alloca = PlaceRef::alloca(self, left.layout);
-            self.typed_place_copy(alloca, left);
+            let alloca = PlaceRef::alloca(self, layout);
+            self.typed_place_copy(alloca.val, left, layout);
             temp = self.load_operand(alloca);
         }
-        self.typed_place_copy(left, right);
-        temp.val.store(self, right);
+        self.typed_place_copy(left, right, layout);
+        temp.val.store(self, right.with_type(layout));
     }
 
     fn select(
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index ccb3562..403f6a7 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -7,7 +7,7 @@
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{self, Ty};
 use rustc_target::abi::call::{ArgAbi, CastTarget, FnAbi, Reg};
-use rustc_target::abi::{AddressSpace, Integer};
+use rustc_target::abi::{AddressSpace, Float, Integer};
 
 // This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use
 // `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves.
@@ -65,6 +65,16 @@
         }
     }
 
+    fn type_from_float(&self, f: Float) -> Self::Type {
+        use Float::*;
+        match f {
+            F16 => self.type_f16(),
+            F32 => self.type_f32(),
+            F64 => self.type_f64(),
+            F128 => self.type_f128(),
+        }
+    }
+
     fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
         ty.needs_drop(self.tcx(), ty::ParamEnv::reveal_all())
     }
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index b79d744..20f0f27 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -69,9 +69,6 @@
     accessing {$allocation} which contains a function
 const_eval_deref_vtable_pointer =
     accessing {$allocation} which contains a vtable
-const_eval_different_allocations =
-    `{$name}` called on pointers into different allocations
-
 const_eval_division_by_zero =
     dividing by zero
 const_eval_division_overflow =
@@ -234,12 +231,18 @@
 const_eval_nullary_intrinsic_fail =
     could not evaluate nullary intrinsic
 
+const_eval_offset_from_different_allocations =
+    `{$name}` called on pointers into different allocations
+const_eval_offset_from_different_integers =
+    `{$name}` called on different pointers without provenance (i.e., without an associated allocation)
 const_eval_offset_from_overflow =
     `{$name}` called when first pointer is too far ahead of second
-
-const_eval_offset_from_test = out-of-bounds `offset_from`
+const_eval_offset_from_test =
+    out-of-bounds `offset_from`
 const_eval_offset_from_underflow =
     `{$name}` called when first pointer is too far before second
+const_eval_offset_from_unsigned_overflow =
+    `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: {$a_offset} < {$b_offset}
 
 const_eval_operator_non_const =
     cannot call non-const operator in {const_eval_const_context}s
@@ -381,8 +384,6 @@
 const_eval_unreachable_unwind =
     unwinding past a stack frame that does not allow unwinding
 
-const_eval_unsigned_offset_from_overflow =
-    `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: {$a_offset} < {$b_offset}
 const_eval_unsized_local = unsized locals are not supported
 const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
 
diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
index afc60d3..94c9f05 100644
--- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs
@@ -1,9 +1,12 @@
-use crate::interpret::{self, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic};
+use crate::interpret::{
+    self, throw_machine_stop, HasStaticRootDefId, ImmTy, Immediate, InterpCx, PointerArithmetic,
+};
 use rustc_middle::mir::interpret::{AllocId, ConstAllocation, InterpResult};
 use rustc_middle::mir::*;
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty;
 use rustc_middle::ty::layout::TyAndLayout;
+use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 
 /// Macro for machine-specific `InterpError` without allocation.
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 2c9eb39..08c9609 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -11,6 +11,7 @@
 
 use super::CompileTimeInterpreter;
 use crate::errors::{self, FrameNote, ReportErrorExt};
+use crate::interpret::{err_inval, err_machine_stop};
 use crate::interpret::{ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType};
 
 /// The CTFE machine has some custom error kinds.
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 71a41e9..6a9a21b 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -3,6 +3,7 @@
 use either::{Left, Right};
 
 use rustc_hir::def::DefKind;
+use rustc_middle::bug;
 use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo};
 use rustc_middle::mir::{self, ConstAlloc, ConstValue};
 use rustc_middle::query::TyCtxtAt;
@@ -24,7 +25,7 @@
     InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
     StackPopCleanup,
 };
-use crate::interpret::{eval_nullary_intrinsic, InternResult};
+use crate::interpret::{eval_nullary_intrinsic, throw_exhaust, InternResult};
 use crate::CTRL_C_RECEIVED;
 
 // Returns a pointer to where the result lives
@@ -222,7 +223,7 @@
                 // This codepath solely exists for `valtree_to_const_value` to not need to generate
                 // a `ConstValue::Indirect` for wide references, so it is tightly restricted to just
                 // that case.
-                let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap().ty; // `false` = no raw ptrs
+                let pointee_ty = imm.layout.ty.builtin_deref(false).unwrap(); // `false` = no raw ptrs
                 debug_assert!(
                     matches!(
                         ecx.tcx.struct_tail_without_normalization(pointee_ty).kind(),
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index ddad668..8c66888 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -81,8 +81,8 @@
                 if cfg!(debug_assertions) && stab.promotable {
                     let sig = tcx.fn_sig(def_id);
                     assert_eq!(
-                        sig.skip_binder().unsafety(),
-                        hir::Unsafety::Normal,
+                        sig.skip_binder().safety(),
+                        hir::Safety::Safe,
                         "don't mark const unsafe fns as promotable",
                         // https://github.com/rust-lang/rust/pull/53851#issuecomment-418760682
                     );
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index 6e6fa70..310fd46 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -10,6 +10,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::LangItem;
+use rustc_middle::bug;
 use rustc_middle::mir;
 use rustc_middle::mir::AssertMessage;
 use rustc_middle::query::TyCtxtAt;
@@ -24,8 +25,9 @@
 use crate::errors::{LongRunning, LongRunningWarn};
 use crate::fluent_generated as fluent;
 use crate::interpret::{
-    self, compile_time_machine, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, FnVal,
-    Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, Scalar,
+    self, compile_time_machine, err_ub, throw_exhaust, throw_inval, throw_ub_custom, throw_unsup,
+    throw_unsup_format, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, FnVal, Frame,
+    GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, Pointer, PointerArithmetic, Scalar,
 };
 
 use super::error::*;
@@ -757,11 +759,21 @@
         ecx: &InterpCx<'mir, 'tcx, Self>,
         alloc_id: AllocId,
     ) -> InterpResult<'tcx> {
+        // Check if this is the currently evaluated static.
         if Some(alloc_id) == ecx.machine.static_root_ids.map(|(id, _)| id) {
-            Err(ConstEvalErrKind::RecursiveStatic.into())
-        } else {
-            Ok(())
+            return Err(ConstEvalErrKind::RecursiveStatic.into());
         }
+        // If this is another static, make sure we fire off the query to detect cycles.
+        // But only do that when checks for static recursion are enabled.
+        if ecx.machine.static_root_ids.is_some() {
+            if let Some(GlobalAlloc::Static(def_id)) = ecx.tcx.try_get_global_alloc(alloc_id) {
+                if ecx.tcx.is_foreign_item(def_id) {
+                    throw_unsup!(ExternStatic(def_id));
+                }
+                ecx.ctfe_query(|tcx| tcx.eval_static_initializer(def_id))?;
+            }
+        }
+        Ok(())
     }
 }
 
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index 8efc67b..a5c8c0b 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -1,5 +1,6 @@
 // Not in interpret to make sure we do not use private implementation details
 
+use rustc_middle::bug;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::InterpErrorInfo;
 use rustc_middle::query::{Key, TyCtxtAt};
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index dcfce4e..fbf2ca5 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -1,4 +1,5 @@
 use rustc_data_structures::stack::ensure_sufficient_stack;
+use rustc_middle::bug;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
 use rustc_middle::ty::layout::{LayoutCx, LayoutOf, TyAndLayout};
diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs
index 76e59ea..799e12f 100644
--- a/compiler/rustc_const_eval/src/interpret/cast.rs
+++ b/compiler/rustc_const_eval/src/interpret/cast.rs
@@ -7,11 +7,13 @@
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::layout::{IntegerExt, LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, FloatTy, Ty};
+use rustc_middle::{bug, span_bug};
 use rustc_target::abi::Integer;
 use rustc_type_ir::TyKind::*;
 
 use super::{
-    util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate, InterpCx, Machine, OpTy, PlaceTy,
+    err_inval, throw_ub, throw_ub_custom, util::ensure_monomorphic_enough, FnVal, ImmTy, Immediate,
+    InterpCx, Machine, OpTy, PlaceTy,
 };
 
 use crate::fluent_generated as fluent;
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index caacc6f..8ddc741 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -1,12 +1,15 @@
 //! Functions for reading and writing discriminants of multi-variant layouts (enums and coroutines).
 
 use rustc_middle::mir;
+use rustc_middle::span_bug;
 use rustc_middle::ty::layout::{LayoutOf, PrimitiveExt};
 use rustc_middle::ty::{self, ScalarInt, Ty};
 use rustc_target::abi::{self, TagEncoding};
 use rustc_target::abi::{VariantIdx, Variants};
 
-use super::{ImmTy, InterpCx, InterpResult, Machine, Readable, Scalar, Writeable};
+use super::{
+    err_ub, throw_ub, ImmTy, InterpCx, InterpResult, Machine, Readable, Scalar, Writeable,
+};
 
 impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
     /// Writes the discriminant of the given variant.
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 126d643..344bb7c 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -17,15 +17,17 @@
     TyAndLayout,
 };
 use rustc_middle::ty::{self, GenericArgsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, Variance};
+use rustc_middle::{bug, span_bug};
 use rustc_mir_dataflow::storage::always_storage_live_locals;
 use rustc_session::Limit;
 use rustc_span::Span;
 use rustc_target::abi::{call::FnAbi, Align, HasDataLayout, Size, TargetDataLayout};
 
 use super::{
-    GlobalId, Immediate, InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta,
-    Memory, MemoryKind, OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic, Projectable,
-    Provenance, Scalar, StackPopJump,
+    err_inval, throw_inval, throw_ub, throw_ub_custom, throw_unsup, GlobalId, Immediate,
+    InterpErrorInfo, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, MemoryKind,
+    OpTy, Operand, Place, PlaceTy, Pointer, PointerArithmetic, Projectable, Provenance, Scalar,
+    StackPopJump,
 };
 use crate::errors;
 use crate::util;
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index d416827..3565b4f 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -24,7 +24,7 @@
 use rustc_span::def_id::LocalDefId;
 use rustc_span::sym;
 
-use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy};
+use super::{err_ub, AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy};
 use crate::const_eval;
 use crate::errors::NestedStaticInThreadLocal;
 
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 88ce5a7..72dad56 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -8,21 +8,18 @@
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_middle::{
-    mir::{
-        self,
-        interpret::{
-            Allocation, ConstAllocation, GlobalId, InterpResult, PointerArithmetic, Scalar,
-        },
-        BinOp, ConstValue, NonDivergingIntrinsic,
-    },
+    bug,
+    mir::{self, BinOp, ConstValue, NonDivergingIntrinsic},
     ty::layout::TyAndLayout,
 };
 use rustc_span::symbol::{sym, Symbol};
 use rustc_target::abi::Size;
 
 use super::{
-    memory::MemoryKind, util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx,
-    MPlaceTy, Machine, OpTy, Pointer,
+    err_inval, err_ub_custom, err_unsup_format, memory::MemoryKind, throw_inval, throw_ub_custom,
+    throw_ub_format, util::ensure_monomorphic_enough, Allocation, CheckInAllocMsg, ConstAllocation,
+    GlobalId, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, Pointer, PointerArithmetic,
+    Scalar,
 };
 
 use crate::fluent_generated as fluent;
@@ -249,14 +246,23 @@
                     match (self.ptr_try_get_alloc_id(a), self.ptr_try_get_alloc_id(b)) {
                         (Err(a), Err(b)) => {
                             // Neither pointer points to an allocation.
-                            // If these are inequal or null, this *will* fail the deref check below.
+                            // This is okay only if they are the same.
+                            if a != b {
+                                // We'd catch this below in the "dereferenceable" check, but
+                                // show a nicer error for this particular case.
+                                throw_ub_custom!(
+                                    fluent::const_eval_offset_from_different_integers,
+                                    name = intrinsic_name,
+                                );
+                            }
+                            // This will always return 0.
                             (a, b)
                         }
                         (Err(_), _) | (_, Err(_)) => {
                             // We managed to find a valid allocation for one pointer, but not the other.
                             // That means they are definitely not pointing to the same allocation.
                             throw_ub_custom!(
-                                fluent::const_eval_different_allocations,
+                                fluent::const_eval_offset_from_different_allocations,
                                 name = intrinsic_name,
                             );
                         }
@@ -264,7 +270,7 @@
                             // Found allocation for both. They must be into the same allocation.
                             if a_alloc_id != b_alloc_id {
                                 throw_ub_custom!(
-                                    fluent::const_eval_different_allocations,
+                                    fluent::const_eval_offset_from_different_allocations,
                                     name = intrinsic_name,
                                 );
                             }
@@ -286,7 +292,7 @@
                         // a < b
                         if intrinsic_name == sym::ptr_offset_from_unsigned {
                             throw_ub_custom!(
-                                fluent::const_eval_unsigned_offset_from_overflow,
+                                fluent::const_eval_offset_from_unsigned_overflow,
                                 a_offset = a_offset,
                                 b_offset = b_offset,
                             );
@@ -602,7 +608,7 @@
         nonoverlapping: bool,
     ) -> InterpResult<'tcx> {
         let count = self.read_target_usize(count)?;
-        let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap().ty)?;
+        let layout = self.layout_of(src.layout.ty.builtin_deref(true).unwrap())?;
         let (size, align) = (layout.size, layout.align.abi);
         // `checked_mul` enforces a too small bound (the correct one would probably be target_isize_max),
         // but no actual allocation can be big enough for the difference to be noticeable.
@@ -646,7 +652,7 @@
         byte: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
         count: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
     ) -> InterpResult<'tcx> {
-        let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap().ty)?;
+        let layout = self.layout_of(dst.layout.ty.builtin_deref(true).unwrap())?;
 
         let dst = self.read_pointer(dst)?;
         let byte = self.read_scalar(byte)?.to_u8()?;
@@ -685,7 +691,7 @@
         lhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
         rhs: &OpTy<'tcx, <M as Machine<'mir, 'tcx>>::Provenance>,
     ) -> InterpResult<'tcx, Scalar<M::Provenance>> {
-        let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap().ty)?;
+        let layout = self.layout_of(lhs.layout.ty.builtin_deref(true).unwrap())?;
         assert!(layout.is_sized());
 
         let get_bytes = |this: &InterpCx<'mir, 'tcx, M>,
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 8405d07..2eaebc1 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -18,9 +18,9 @@
 use rustc_target::spec::abi::Abi as CallAbi;
 
 use super::{
-    AllocBytes, AllocId, AllocKind, AllocRange, Allocation, ConstAllocation, CtfeProvenance, FnArg,
-    Frame, ImmTy, InterpCx, InterpResult, MPlaceTy, MemoryKind, Misalignment, OpTy, PlaceTy,
-    Pointer, Provenance,
+    throw_unsup, throw_unsup_format, AllocBytes, AllocId, AllocKind, AllocRange, Allocation,
+    ConstAllocation, CtfeProvenance, FnArg, Frame, ImmTy, InterpCx, InterpResult, MPlaceTy,
+    MemoryKind, Misalignment, OpTy, PlaceTy, Pointer, Provenance,
 };
 
 /// Data returned by Machine::stack_pop,
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 594e3b3..737f2fd 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -16,6 +16,7 @@
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_hir::def::DefKind;
+use rustc_middle::bug;
 use rustc_middle::mir::display_allocation;
 use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TyCtxt};
 use rustc_target::abi::{Align, HasDataLayout, Size};
@@ -23,9 +24,10 @@
 use crate::fluent_generated as fluent;
 
 use super::{
-    alloc_range, AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg,
-    CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak,
-    Misalignment, Pointer, PointerArithmetic, Provenance, Scalar,
+    alloc_range, err_ub, err_ub_custom, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
+    AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, CheckInAllocMsg,
+    CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer,
+    PointerArithmetic, Provenance, Scalar,
 };
 
 #[derive(Debug, PartialEq, Copy, Clone)]
@@ -411,6 +413,8 @@
     /// to the allocation it points to. Supports both shared and mutable references, as the actual
     /// checking is offloaded to a helper closure.
     ///
+    /// `alloc_size` will only get called for non-zero-sized accesses.
+    ///
     /// Returns `None` if and only if the size is 0.
     fn check_and_deref_ptr<T>(
         &self,
@@ -423,18 +427,19 @@
             M::ProvenanceExtra,
         ) -> InterpResult<'tcx, (Size, Align, T)>,
     ) -> InterpResult<'tcx, Option<T>> {
+        // Everything is okay with size 0.
+        if size.bytes() == 0 {
+            return Ok(None);
+        }
+
         Ok(match self.ptr_try_get_alloc_id(ptr) {
             Err(addr) => {
-                // We couldn't get a proper allocation. This is only okay if the access size is 0,
-                // and the address is not null.
-                if size.bytes() > 0 || addr == 0 {
-                    throw_ub!(DanglingIntPointer(addr, msg));
-                }
-                None
+                // We couldn't get a proper allocation.
+                throw_ub!(DanglingIntPointer(addr, msg));
             }
             Ok((alloc_id, offset, prov)) => {
                 let (alloc_size, _alloc_align, ret_val) = alloc_size(alloc_id, offset, prov)?;
-                // Test bounds. This also ensures non-null.
+                // Test bounds.
                 // It is sufficient to check this for the end pointer. Also check for overflow!
                 if offset.checked_add(size, &self.tcx).map_or(true, |end| end > alloc_size) {
                     throw_ub!(PointerOutOfBounds {
@@ -445,14 +450,8 @@
                         msg,
                     })
                 }
-                // Ensure we never consider the null pointer dereferenceable.
-                if M::Provenance::OFFSET_IS_ADDR {
-                    assert_ne!(ptr.addr(), Size::ZERO);
-                }
 
-                // We can still be zero-sized in this branch, in which case we have to
-                // return `None`.
-                if size.bytes() == 0 { None } else { Some(ret_val) }
+                Some(ret_val)
             }
         })
     }
@@ -639,16 +638,18 @@
             size,
             CheckInAllocMsg::MemoryAccessTest,
             |alloc_id, offset, prov| {
-                if !self.memory.validation_in_progress.get() {
-                    // We want to call the hook on *all* accesses that involve an AllocId,
-                    // including zero-sized accesses. That means we have to do it here
-                    // rather than below in the `Some` branch.
-                    M::before_alloc_read(self, alloc_id)?;
-                }
                 let alloc = self.get_alloc_raw(alloc_id)?;
                 Ok((alloc.size(), alloc.align, (alloc_id, offset, prov, alloc)))
             },
         )?;
+        // We want to call the hook on *all* accesses that involve an AllocId, including zero-sized
+        // accesses. That means we cannot rely on the closure above or the `Some` branch below. We
+        // do this after `check_and_deref_ptr` to ensure some basic sanity has already been checked.
+        if !self.memory.validation_in_progress.get() {
+            if let Ok((alloc_id, ..)) = self.ptr_try_get_alloc_id(ptr) {
+                M::before_alloc_read(self, alloc_id)?;
+            }
+        }
 
         if let Some((alloc_id, offset, prov, alloc)) = ptr_and_alloc {
             let range = alloc_range(offset, size);
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 718c91b..bad9732 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -10,13 +10,14 @@
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter};
 use rustc_middle::ty::{ConstInt, ScalarInt, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_middle::{mir, ty};
 use rustc_target::abi::{self, Abi, HasDataLayout, Size};
 
 use super::{
-    alloc_range, from_known_layout, mir_assign_valid_types, CtfeProvenance, InterpCx, InterpResult,
-    MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy, Pointer, Projectable,
-    Provenance, Scalar,
+    alloc_range, err_ub, from_known_layout, mir_assign_valid_types, throw_ub, CtfeProvenance,
+    InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, MemPlaceMeta, OffsetMode, PlaceTy,
+    Pointer, Projectable, Provenance, Scalar,
 };
 
 /// An `Immediate` represents a single immediate self-contained Rust value.
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 9af755e..5f59e3d 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -3,10 +3,11 @@
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::{self, FloatTy, ScalarInt, Ty};
+use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::sym;
 use rustc_target::abi::Abi;
 
-use super::{ImmTy, Immediate, InterpCx, Machine, PlaceTy};
+use super::{err_ub, throw_ub, throw_ub_custom, ImmTy, Immediate, InterpCx, Machine, PlaceTy};
 
 use crate::fluent_generated as fluent;
 
@@ -357,7 +358,7 @@
             Offset => {
                 let ptr = left.to_scalar().to_pointer(self)?;
                 let offset_count = right.to_scalar().to_target_isize(self)?;
-                let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty;
+                let pointee_ty = left.layout.ty.builtin_deref(true).unwrap();
 
                 // We cannot overflow i64 as a type's size must be <= isize::MAX.
                 let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap();
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index e5241f1..9ced825 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -11,12 +11,14 @@
 use rustc_middle::ty;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::Ty;
+use rustc_middle::{bug, span_bug};
 use rustc_target::abi::{Abi, Align, HasDataLayout, Size};
 
 use super::{
-    alloc_range, mir_assign_valid_types, AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance,
-    ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy,
-    Operand, Pointer, PointerArithmetic, Projectable, Provenance, Readable, Scalar,
+    alloc_range, mir_assign_valid_types, throw_ub, AllocRef, AllocRefMut, CheckAlignMsg,
+    CtfeProvenance, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemoryKind, Misalignment,
+    OffsetMode, OpTy, Operand, Pointer, PointerArithmetic, Projectable, Provenance, Readable,
+    Scalar,
 };
 
 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
@@ -415,7 +417,7 @@
         val: &ImmTy<'tcx, M::Provenance>,
     ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::Provenance>> {
         let pointee_type =
-            val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type").ty;
+            val.layout.ty.builtin_deref(true).expect("`ref_to_mplace` called on non-ptr type");
         let layout = self.layout_of(pointee_type)?;
         let (ptr, meta) = val.to_scalar_and_meta();
 
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 5ff78f7..0a2fedb 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -14,10 +14,14 @@
 use rustc_middle::ty;
 use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
 use rustc_middle::ty::Ty;
+use rustc_middle::{bug, span_bug};
 use rustc_target::abi::Size;
 use rustc_target::abi::{self, VariantIdx};
 
-use super::{InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Provenance, Scalar};
+use super::{
+    throw_ub, throw_unsup_format, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
+    Provenance, Scalar,
+};
 
 /// Describes the constraints placed on offset-projections.
 #[derive(Copy, Clone, Debug)]
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index b29034e..cb72d55 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -7,6 +7,7 @@
 use rustc_index::IndexSlice;
 use rustc_middle::mir;
 use rustc_middle::ty::layout::LayoutOf;
+use rustc_middle::{bug, span_bug};
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
 
 use super::{
@@ -166,15 +167,11 @@
                 let left = self.read_immediate(&self.eval_operand(left, layout)?)?;
                 let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout);
                 let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
-                self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
-            }
-
-            CheckedBinaryOp(bin_op, box (ref left, ref right)) => {
-                // Due to the extra boolean in the result, we can never reuse the `dest.layout`.
-                let left = self.read_immediate(&self.eval_operand(left, None)?)?;
-                let layout = util::binop_right_homogeneous(bin_op).then_some(left.layout);
-                let right = self.read_immediate(&self.eval_operand(right, layout)?)?;
-                self.binop_with_overflow(bin_op, &left, &right, &dest)?;
+                if let Some(bin_op) = bin_op.overflowing_to_wrapping() {
+                    self.binop_with_overflow(bin_op, &left, &right, &dest)?;
+                } else {
+                    self.binop_ignore_overflow(bin_op, &left, &right, &dest)?;
+                }
             }
 
             UnaryOp(un_op, ref operand) => {
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index b474003..b82c185 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -2,6 +2,7 @@
 
 use either::Either;
 
+use rustc_middle::span_bug;
 use rustc_middle::{
     mir,
     ty::{
@@ -19,8 +20,9 @@
 use rustc_target::spec::abi::Abi;
 
 use super::{
-    CtfeProvenance, FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy,
-    Projectable, Provenance, Scalar, StackPopCleanup,
+    throw_ub, throw_ub_custom, throw_unsup_format, CtfeProvenance, FnVal, ImmTy, InterpCx,
+    InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, Projectable, Provenance, Scalar,
+    StackPopCleanup,
 };
 use crate::fluent_generated as fluent;
 
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index c83ef14..e304d1e 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -1,5 +1,4 @@
 use crate::const_eval::{CompileTimeEvalContext, CompileTimeInterpreter, InterpretationResult};
-use crate::interpret::{MemPlaceMeta, MemoryKind};
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::{Allocation, InterpResult, Pointer};
@@ -9,7 +8,7 @@
 };
 use std::ops::ControlFlow;
 
-use super::{InterpCx, MPlaceTy};
+use super::{throw_inval, InterpCx, MPlaceTy, MemPlaceMeta, MemoryKind};
 
 /// Checks whether a type contains generic parameters which must be instantiated.
 ///
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 1456671..e36d301 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -13,6 +13,7 @@
 use rustc_ast::Mutability;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
+use rustc_middle::bug;
 use rustc_middle::mir::interpret::{
     ExpectedKind, InterpError, InvalidMetaKind, Misalignment, PointerKind, Provenance,
     ValidationErrorInfo, ValidationErrorKind, ValidationErrorKind::*,
@@ -27,9 +28,9 @@
 use std::hash::Hash;
 
 use super::{
-    format_interp_error, machine::AllocMap, AllocId, CheckInAllocMsg, GlobalAlloc, ImmTy,
-    Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, Pointer, Projectable,
-    Scalar, ValueVisitor,
+    err_ub, format_interp_error, machine::AllocMap, throw_ub, AllocId, CheckInAllocMsg,
+    GlobalAlloc, ImmTy, Immediate, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy,
+    Pointer, Projectable, Scalar, ValueVisitor,
 };
 
 // for the validation errors
@@ -433,6 +434,11 @@
                 found_bytes: has.bytes()
             },
         );
+        // Make sure this is non-null. We checked dereferenceability above, but if `size` is zero
+        // that does not imply non-null.
+        if self.ecx.scalar_may_be_null(Scalar::from_maybe_pointer(place.ptr(), self.ecx))? {
+            throw_validation_failure!(self.path, NullPtr { ptr_kind })
+        }
         // Do not allow pointers to uninhabited types.
         if place.layout.abi.is_uninhabited() {
             let ty = place.layout.ty;
@@ -455,8 +461,8 @@
             // `!` is a ZST and we want to validate it.
             if let Ok((alloc_id, _offset, _prov)) = self.ecx.ptr_try_get_alloc_id(place.ptr()) {
                 let mut skip_recursive_check = false;
-                let alloc_actual_mutbl = mutability(self.ecx, alloc_id);
-                if let GlobalAlloc::Static(did) = self.ecx.tcx.global_alloc(alloc_id) {
+                if let Some(GlobalAlloc::Static(did)) = self.ecx.tcx.try_get_global_alloc(alloc_id)
+                {
                     let DefKind::Static { nested, .. } = self.ecx.tcx.def_kind(did) else { bug!() };
                     // Special handling for pointers to statics (irrespective of their type).
                     assert!(!self.ecx.tcx.is_thread_local_static(did));
@@ -494,6 +500,7 @@
                 // If this allocation has size zero, there is no actual mutability here.
                 let (size, _align, _alloc_kind) = self.ecx.get_alloc_info(alloc_id);
                 if size != Size::ZERO {
+                    let alloc_actual_mutbl = mutability(self.ecx, alloc_id);
                     // Mutable pointer to immutable memory is no good.
                     if ptr_expected_mutbl == Mutability::Mut
                         && alloc_actual_mutbl == Mutability::Not
@@ -830,6 +837,8 @@
         trace!("visit_value: {:?}, {:?}", *op, op.layout);
 
         // Check primitive types -- the leaves of our recursive descent.
+        // We assume that the Scalar validity range does not restrict these values
+        // any further than `try_visit_primitive` does!
         if self.try_visit_primitive(op)? {
             return Ok(());
         }
diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index 84557b8..59bcc51 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -9,7 +9,7 @@
 
 use std::num::NonZero;
 
-use super::{InterpCx, MPlaceTy, Machine, Projectable};
+use super::{throw_inval, InterpCx, MPlaceTy, Machine, Projectable};
 
 /// How to traverse a value and what to do when we are at the leaves.
 pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index d27d427..7b293e2 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -1,9 +1,3 @@
-/*!
-
-Rust MIR: a lowered representation of Rust.
-
-*/
-
 #![allow(internal_features)]
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![feature(rustdoc_internals)]
@@ -22,8 +16,6 @@
 
 #[macro_use]
 extern crate tracing;
-#[macro_use]
-extern crate rustc_middle;
 
 pub mod const_eval;
 mod errors;
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index f9786ac..c8c5414 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -8,10 +8,11 @@
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
+use rustc_middle::span_bug;
 use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt};
 use rustc_middle::ty::{Instance, InstanceDef, TypeVisitableExt};
 use rustc_mir_dataflow::Analysis;
-use rustc_span::{sym, Span, Symbol};
+use rustc_span::{sym, Span, Symbol, DUMMY_SP};
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
 use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt};
 use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitor};
@@ -579,7 +580,7 @@
                 }
             }
 
-            Rvalue::BinaryOp(op, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => {
+            Rvalue::BinaryOp(op, box (lhs, rhs)) => {
                 let lhs_ty = lhs.ty(self.body, self.tcx);
                 let rhs_ty = rhs.ty(self.body, self.tcx);
 
@@ -738,7 +739,7 @@
                 let cause = ObligationCause::new(
                     terminator.source_info.span,
                     self.body.source.def_id().expect_local(),
-                    ObligationCauseCode::ItemObligation(callee),
+                    ObligationCauseCode::WhereClause(callee, DUMMY_SP),
                 );
                 let normalized_predicates = ocx.normalize(&cause, param_env, predicates);
                 ocx.register_obligations(traits::predicates_for_generics(
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index 12e7ec1..308b90c 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -8,6 +8,7 @@
 use rustc_errors::DiagCtxt;
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_middle::bug;
 use rustc_middle::mir;
 use rustc_middle::ty::{self, PolyFnSig, TyCtxt};
 use rustc_span::Symbol;
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index dda8f3e..8775685 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -8,7 +8,8 @@
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{ImplSource, Obligation, ObligationCause};
 use rustc_middle::mir::{self, CallSource};
-use rustc_middle::ty::print::with_no_trimmed_paths;
+use rustc_middle::span_bug;
+use rustc_middle::ty::print::{with_no_trimmed_paths, PrintTraitRefExt as _};
 use rustc_middle::ty::{
     self, suggest_constraining_type_param, Closure, FnDef, FnPtr, GenericArgKind, GenericArgsRef,
     Param, TraitRef, Ty,
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 1847847..7e8a208 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -5,6 +5,7 @@
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::LangItem;
 use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::bug;
 use rustc_middle::mir;
 use rustc_middle::mir::*;
 use rustc_middle::traits::BuiltinImplSource;
@@ -260,7 +261,7 @@
         | Rvalue::Cast(_, operand, _)
         | Rvalue::ShallowInitBox(operand, _) => in_operand::<Q, _>(cx, in_local, operand),
 
-        Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
+        Rvalue::BinaryOp(_, box (lhs, rhs)) => {
             in_operand::<Q, _>(cx, in_local, lhs) || in_operand::<Q, _>(cx, in_local, rhs)
         }
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index 5ae3ffa..0113414 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -200,7 +200,6 @@
             | mir::Rvalue::Repeat(..)
             | mir::Rvalue::Len(..)
             | mir::Rvalue::BinaryOp(..)
-            | mir::Rvalue::CheckedBinaryOp(..)
             | mir::Rvalue::NullaryOp(..)
             | mir::Rvalue::UnaryOp(..)
             | mir::Rvalue::Discriminant(..)
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index 837c02a..3a2b2c5 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -9,6 +9,7 @@
 use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt, Variance};
+use rustc_middle::{bug, span_bug};
 use rustc_target::abi::{Size, FIRST_VARIANT};
 use rustc_target::spec::abi::Abi;
 
@@ -1036,8 +1037,8 @@
                             )
                         }
                     }
-                    AddUnchecked | SubUnchecked | MulUnchecked | Shl | ShlUnchecked | Shr
-                    | ShrUnchecked => {
+                    AddUnchecked | AddWithOverflow | SubUnchecked | SubWithOverflow
+                    | MulUnchecked | MulWithOverflow | Shl | ShlUnchecked | Shr | ShrUnchecked => {
                         for x in [a, b] {
                             check_kinds!(
                                 x,
@@ -1066,31 +1067,6 @@
                     }
                 }
             }
-            Rvalue::CheckedBinaryOp(op, vals) => {
-                use BinOp::*;
-                let a = vals.0.ty(&self.body.local_decls, self.tcx);
-                let b = vals.1.ty(&self.body.local_decls, self.tcx);
-                match op {
-                    Add | Sub | Mul => {
-                        for x in [a, b] {
-                            check_kinds!(
-                                x,
-                                "Cannot perform checked arithmetic on type {:?}",
-                                ty::Uint(..) | ty::Int(..)
-                            )
-                        }
-                        if a != b {
-                            self.fail(
-                                location,
-                                format!(
-                                    "Cannot perform checked arithmetic on unequal types {a:?} and {b:?}"
-                                ),
-                            );
-                        }
-                    }
-                    _ => self.fail(location, format!("There is no checked version of {op:?}")),
-                }
-            }
             Rvalue::UnaryOp(op, operand) => {
                 let a = operand.ty(&self.body.local_decls, self.tcx);
                 match op {
@@ -1291,7 +1267,7 @@
             )) => {
                 let src_ty = src.ty(&self.body.local_decls, self.tcx);
                 let op_src_ty = if let Some(src_deref) = src_ty.builtin_deref(true) {
-                    src_deref.ty
+                    src_deref
                 } else {
                     self.fail(
                         location,
@@ -1301,7 +1277,7 @@
                 };
                 let dst_ty = dst.ty(&self.body.local_decls, self.tcx);
                 let op_dst_ty = if let Some(dst_deref) = dst_ty.builtin_deref(true) {
-                    dst_deref.ty
+                    dst_deref
                 } else {
                     self.fail(
                         location,
diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs
index af9a4a4..403bc1e 100644
--- a/compiler/rustc_const_eval/src/util/caller_location.rs
+++ b/compiler/rustc_const_eval/src/util/caller_location.rs
@@ -1,4 +1,5 @@
 use rustc_hir::LangItem;
+use rustc_middle::bug;
 use rustc_middle::mir;
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::ty::layout::LayoutOf;
diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
index 8c4af5e..68fb122 100644
--- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
+++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs
@@ -1,3 +1,4 @@
+use rustc_middle::bug;
 use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, ValidityRequirement};
 use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt};
 use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants};
@@ -115,7 +116,7 @@
 
     // Special magic check for references and boxes (i.e., special pointer types).
     if let Some(pointee) = this.ty.builtin_deref(false) {
-        let pointee = cx.layout_of(pointee.ty)?;
+        let pointee = cx.layout_of(pointee)?;
         // We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied.
         if pointee.align.abi.bytes() > 1 {
             // 0x01-filling is not aligned.
diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs
index 0c3b59a..66a1add 100644
--- a/compiler/rustc_const_eval/src/util/mod.rs
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -19,7 +19,9 @@
     match op {
         Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
         | BitAnd | BitOr | Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => true,
-        Eq | Ne | Lt | Le | Gt | Ge | Cmp => false,
+        AddWithOverflow | SubWithOverflow | MulWithOverflow | Eq | Ne | Lt | Le | Gt | Ge | Cmp => {
+            false
+        }
     }
 }
 
@@ -29,8 +31,9 @@
 pub fn binop_right_homogeneous(op: mir::BinOp) -> bool {
     use rustc_middle::mir::BinOp::*;
     match op {
-        Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
-        | BitAnd | BitOr | Eq | Ne | Lt | Le | Gt | Ge | Cmp => true,
+        Add | AddUnchecked | AddWithOverflow | Sub | SubUnchecked | SubWithOverflow | Mul
+        | MulUnchecked | MulWithOverflow | Div | Rem | BitXor | BitAnd | BitOr | Eq | Ne | Lt
+        | Le | Gt | Ge | Cmp => true,
         Offset | Shl | ShlUnchecked | Shr | ShrUnchecked => false,
     }
 }
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index e474b95..01e5172 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -1,6 +1,7 @@
 use rustc_data_structures::intern::Interned;
 use rustc_hir::def_id::CrateNum;
 use rustc_hir::definitions::DisambiguatedDefPathData;
+use rustc_middle::bug;
 use rustc_middle::ty::{
     self,
     print::{PrettyPrinter, Print, PrintError, Printer},
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 80b6e72..2b61e17 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -9,7 +9,7 @@
 bitflags = "2.4.1"
 either = "1.0"
 elsa = "=1.7.1"
-ena = "0.14.2"
+ena = "0.14.3"
 indexmap = { version = "2.0.0" }
 jobserver_crate = { version = "0.1.28", package = "jobserver" }
 libc = "0.2"
diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs
index 9995c08..1bee159 100644
--- a/compiler/rustc_data_structures/src/fingerprint.rs
+++ b/compiler/rustc_data_structures/src/fingerprint.rs
@@ -1,3 +1,4 @@
+use crate::stable_hasher::impl_stable_traits_for_trivial_type;
 use crate::stable_hasher::{Hash64, StableHasher, StableHasherResult};
 use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
 use std::hash::{Hash, Hasher};
diff --git a/compiler/rustc_data_structures/src/flock/windows.rs b/compiler/rustc_data_structures/src/flock/windows.rs
index 9be1065..7dc7266 100644
--- a/compiler/rustc_data_structures/src/flock/windows.rs
+++ b/compiler/rustc_data_structures/src/flock/windows.rs
@@ -2,6 +2,7 @@
 use std::io;
 use std::os::windows::prelude::*;
 use std::path::Path;
+use tracing::debug;
 
 use windows::{
     Win32::Foundation::{ERROR_INVALID_FUNCTION, HANDLE},
diff --git a/compiler/rustc_data_structures/src/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/implementation/mod.rs
index 3910c6f..8cf4b41 100644
--- a/compiler/rustc_data_structures/src/graph/implementation/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/implementation/mod.rs
@@ -22,6 +22,7 @@
 
 use rustc_index::bit_set::BitSet;
 use std::fmt::Debug;
+use tracing::debug;
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_data_structures/src/graph/implementation/tests.rs b/compiler/rustc_data_structures/src/graph/implementation/tests.rs
index 3ae5f58..b4dbd65 100644
--- a/compiler/rustc_data_structures/src/graph/implementation/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/implementation/tests.rs
@@ -1,4 +1,5 @@
 use crate::graph::implementation::*;
+use tracing::debug;
 
 type TestGraph = Graph<&'static str, &'static str>;
 
diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs
index 5021e5e..914a6a1 100644
--- a/compiler/rustc_data_structures/src/graph/scc/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs
@@ -10,6 +10,7 @@
 use crate::graph::{DirectedGraph, NumEdges, Successors};
 use rustc_index::{Idx, IndexSlice, IndexVec};
 use std::ops::Range;
+use tracing::{debug, instrument};
 
 #[cfg(test)]
 mod tests;
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index 8dd85b2..85b5a3c 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -42,12 +42,52 @@
 #![feature(unwrap_infallible)]
 // tidy-alphabetical-end
 
-#[macro_use]
-extern crate tracing;
+pub use atomic_ref::AtomicRef;
+pub use ena::snapshot_vec;
+pub use ena::undo_log;
+pub use ena::unify;
+pub use rustc_index::static_assert_size;
 
 use std::fmt;
 
-pub use rustc_index::static_assert_size;
+pub mod aligned;
+pub mod base_n;
+pub mod binary_search_util;
+pub mod captures;
+pub mod fingerprint;
+pub mod flat_map_in_place;
+pub mod flock;
+pub mod frozen;
+pub mod fx;
+pub mod graph;
+pub mod intern;
+pub mod jobserver;
+pub mod marker;
+pub mod memmap;
+pub mod obligation_forest;
+pub mod owned_slice;
+pub mod packed;
+pub mod profiling;
+pub mod sharded;
+pub mod sip128;
+pub mod small_c_str;
+pub mod snapshot_map;
+pub mod sorted_map;
+pub mod sso;
+pub mod stable_hasher;
+pub mod stack;
+pub mod steal;
+pub mod svh;
+pub mod sync;
+pub mod tagged_ptr;
+pub mod temp_dir;
+pub mod transitive_relation;
+pub mod unhash;
+pub mod unord;
+pub mod work_queue;
+
+mod atomic_ref;
+mod hashes;
 
 /// This calls the passed function while ensuring it won't be inlined into the caller.
 #[inline(never)]
@@ -56,53 +96,6 @@
     f()
 }
 
-pub mod base_n;
-pub mod binary_search_util;
-pub mod captures;
-pub mod flat_map_in_place;
-pub mod flock;
-pub mod fx;
-pub mod graph;
-pub mod intern;
-pub mod jobserver;
-pub mod macros;
-pub mod obligation_forest;
-pub mod sip128;
-pub mod small_c_str;
-pub mod snapshot_map;
-pub mod svh;
-pub use ena::snapshot_vec;
-pub mod memmap;
-pub mod sorted_map;
-#[macro_use]
-pub mod stable_hasher;
-mod atomic_ref;
-pub mod fingerprint;
-pub mod marker;
-pub mod profiling;
-pub mod sharded;
-pub mod stack;
-pub mod sync;
-pub mod tiny_list;
-pub mod transitive_relation;
-pub mod vec_linked_list;
-pub mod work_queue;
-pub use atomic_ref::AtomicRef;
-pub mod aligned;
-pub mod frozen;
-mod hashes;
-pub mod owned_slice;
-pub mod packed;
-pub mod sso;
-pub mod steal;
-pub mod tagged_ptr;
-pub mod temp_dir;
-pub mod unhash;
-pub mod unord;
-
-pub use ena::undo_log;
-pub use ena::unify;
-
 /// Returns a structure that calls `f` when dropped.
 pub fn defer<F: FnOnce()>(f: F) -> OnDrop<F> {
     OnDrop(Some(f))
diff --git a/compiler/rustc_data_structures/src/macros.rs b/compiler/rustc_data_structures/src/macros.rs
deleted file mode 100644
index e05491f..0000000
--- a/compiler/rustc_data_structures/src/macros.rs
+++ /dev/null
@@ -1,37 +0,0 @@
-#[macro_export]
-macro_rules! enum_from_u32 {
-    ($(#[$attr:meta])* pub enum $name:ident {
-        $($(#[$var_attr:meta])* $variant:ident = $e:expr,)*
-    }) => {
-        $(#[$attr])*
-        pub enum $name {
-            $($(#[$var_attr])* $variant = $e),*
-        }
-
-        impl $name {
-            pub fn from_u32(u: u32) -> Option<$name> {
-                $(if u == $name::$variant as u32 {
-                    return Some($name::$variant)
-                })*
-                None
-            }
-        }
-    };
-    ($(#[$attr:meta])* pub enum $name:ident {
-        $($(#[$var_attr:meta])* $variant:ident,)*
-    }) => {
-        $(#[$attr])*
-        pub enum $name {
-            $($(#[$var_attr])* $variant,)*
-        }
-
-        impl $name {
-            pub fn from_u32(u: u32) -> Option<$name> {
-                $(if u == $name::$variant as u32 {
-                    return Some($name::$variant)
-                })*
-                None
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index a479086..d477b86 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -70,12 +70,12 @@
 //! aren't needed anymore.
 
 use crate::fx::{FxHashMap, FxHashSet};
-
 use std::cell::Cell;
 use std::collections::hash_map::Entry;
 use std::fmt::Debug;
 use std::hash;
 use std::marker::PhantomData;
+use tracing::debug;
 
 mod graphviz;
 
diff --git a/compiler/rustc_data_structures/src/packed.rs b/compiler/rustc_data_structures/src/packed.rs
index b8d4b29..0a392d9 100644
--- a/compiler/rustc_data_structures/src/packed.rs
+++ b/compiler/rustc_data_structures/src/packed.rs
@@ -3,8 +3,10 @@
 use std::cmp::Ordering;
 use std::fmt;
 
-#[repr(packed(8))]
+/// A packed 128-bit integer. Useful for reducing the size of structures in
+/// some cases.
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
+#[repr(packed(8))]
 pub struct Pu128(pub u128);
 
 impl Pu128 {
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 2569684..c6d51a5 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -99,6 +99,7 @@
 use measureme::{EventIdBuilder, Profiler, SerializableString, StringId};
 use parking_lot::RwLock;
 use smallvec::SmallVec;
+use tracing::warn;
 
 bitflags::bitflags! {
     #[derive(Clone, Copy)]
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 8418b4b..b5bdf2e 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -296,6 +296,8 @@
     };
 }
 
+pub(crate) use impl_stable_traits_for_trivial_type;
+
 impl_stable_traits_for_trivial_type!(i8);
 impl_stable_traits_for_trivial_type!(i16);
 impl_stable_traits_for_trivial_type!(i32);
diff --git a/compiler/rustc_data_structures/src/tiny_list.rs b/compiler/rustc_data_structures/src/tiny_list.rs
deleted file mode 100644
index 11a408f..0000000
--- a/compiler/rustc_data_structures/src/tiny_list.rs
+++ /dev/null
@@ -1,80 +0,0 @@
-//! A singly-linked list.
-//!
-//! Using this data structure only makes sense under very specific
-//! circumstances:
-//!
-//! - If you have a list that rarely stores more than one element, then this
-//!   data-structure can store the element without allocating and only uses as
-//!   much space as an `Option<(T, usize)>`. If T can double as the `Option`
-//!   discriminant, it will even only be as large as `T, usize`.
-//!
-//! If you expect to store more than 1 element in the common case, steer clear
-//! and use a `Vec<T>`, `Box<[T]>`, or a `SmallVec<T>`.
-
-#[cfg(test)]
-mod tests;
-
-#[derive(Clone)]
-pub struct TinyList<T> {
-    head: Option<Element<T>>,
-}
-
-impl<T: PartialEq> TinyList<T> {
-    #[inline]
-    pub fn new() -> TinyList<T> {
-        TinyList { head: None }
-    }
-
-    #[inline]
-    pub fn new_single(data: T) -> TinyList<T> {
-        TinyList { head: Some(Element { data, next: None }) }
-    }
-
-    #[inline]
-    pub fn insert(&mut self, data: T) {
-        self.head = Some(Element { data, next: self.head.take().map(Box::new) });
-    }
-
-    #[inline]
-    pub fn remove(&mut self, data: &T) -> bool {
-        self.head = match &mut self.head {
-            Some(head) if head.data == *data => head.next.take().map(|x| *x),
-            Some(head) => return head.remove_next(data),
-            None => return false,
-        };
-        true
-    }
-
-    #[inline]
-    pub fn contains(&self, data: &T) -> bool {
-        let mut elem = self.head.as_ref();
-        while let Some(e) = elem {
-            if &e.data == data {
-                return true;
-            }
-            elem = e.next.as_deref();
-        }
-        false
-    }
-}
-
-#[derive(Clone)]
-struct Element<T> {
-    data: T,
-    next: Option<Box<Element<T>>>,
-}
-
-impl<T: PartialEq> Element<T> {
-    fn remove_next(mut self: &mut Self, data: &T) -> bool {
-        loop {
-            match self.next {
-                Some(ref mut next) if next.data == *data => {
-                    self.next = next.next.take();
-                    return true;
-                }
-                Some(ref mut next) => self = next,
-                None => return false,
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_data_structures/src/tiny_list/tests.rs b/compiler/rustc_data_structures/src/tiny_list/tests.rs
deleted file mode 100644
index 4b95e62..0000000
--- a/compiler/rustc_data_structures/src/tiny_list/tests.rs
+++ /dev/null
@@ -1,155 +0,0 @@
-use super::*;
-
-extern crate test;
-use test::{black_box, Bencher};
-
-impl<T> TinyList<T> {
-    fn len(&self) -> usize {
-        let (mut elem, mut count) = (self.head.as_ref(), 0);
-        while let Some(e) = elem {
-            count += 1;
-            elem = e.next.as_deref();
-        }
-        count
-    }
-}
-
-#[test]
-fn test_contains_and_insert() {
-    fn do_insert(i: u32) -> bool {
-        i % 2 == 0
-    }
-
-    let mut list = TinyList::new();
-
-    for i in 0..10 {
-        for j in 0..i {
-            if do_insert(j) {
-                assert!(list.contains(&j));
-            } else {
-                assert!(!list.contains(&j));
-            }
-        }
-
-        assert!(!list.contains(&i));
-
-        if do_insert(i) {
-            list.insert(i);
-            assert!(list.contains(&i));
-        }
-    }
-}
-
-#[test]
-fn test_remove_first() {
-    let mut list = TinyList::new();
-    list.insert(1);
-    list.insert(2);
-    list.insert(3);
-    list.insert(4);
-    assert_eq!(list.len(), 4);
-
-    assert!(list.remove(&4));
-    assert!(!list.contains(&4));
-
-    assert_eq!(list.len(), 3);
-    assert!(list.contains(&1));
-    assert!(list.contains(&2));
-    assert!(list.contains(&3));
-}
-
-#[test]
-fn test_remove_last() {
-    let mut list = TinyList::new();
-    list.insert(1);
-    list.insert(2);
-    list.insert(3);
-    list.insert(4);
-    assert_eq!(list.len(), 4);
-
-    assert!(list.remove(&1));
-    assert!(!list.contains(&1));
-
-    assert_eq!(list.len(), 3);
-    assert!(list.contains(&2));
-    assert!(list.contains(&3));
-    assert!(list.contains(&4));
-}
-
-#[test]
-fn test_remove_middle() {
-    let mut list = TinyList::new();
-    list.insert(1);
-    list.insert(2);
-    list.insert(3);
-    list.insert(4);
-    assert_eq!(list.len(), 4);
-
-    assert!(list.remove(&2));
-    assert!(!list.contains(&2));
-
-    assert_eq!(list.len(), 3);
-    assert!(list.contains(&1));
-    assert!(list.contains(&3));
-    assert!(list.contains(&4));
-}
-
-#[test]
-fn test_remove_single() {
-    let mut list = TinyList::new();
-    list.insert(1);
-    assert_eq!(list.len(), 1);
-
-    assert!(list.remove(&1));
-    assert!(!list.contains(&1));
-
-    assert_eq!(list.len(), 0);
-}
-
-#[bench]
-fn bench_insert_empty(b: &mut Bencher) {
-    b.iter(|| {
-        let mut list = black_box(TinyList::new());
-        list.insert(1);
-        list
-    })
-}
-
-#[bench]
-fn bench_insert_one(b: &mut Bencher) {
-    b.iter(|| {
-        let mut list = black_box(TinyList::new_single(0));
-        list.insert(1);
-        list
-    })
-}
-
-#[bench]
-fn bench_contains_empty(b: &mut Bencher) {
-    b.iter(|| black_box(TinyList::new()).contains(&1));
-}
-
-#[bench]
-fn bench_contains_unknown(b: &mut Bencher) {
-    b.iter(|| black_box(TinyList::new_single(0)).contains(&1));
-}
-
-#[bench]
-fn bench_contains_one(b: &mut Bencher) {
-    b.iter(|| black_box(TinyList::new_single(1)).contains(&1));
-}
-
-#[bench]
-fn bench_remove_empty(b: &mut Bencher) {
-    b.iter(|| black_box(TinyList::new()).remove(&1));
-}
-
-#[bench]
-fn bench_remove_unknown(b: &mut Bencher) {
-    b.iter(|| black_box(TinyList::new_single(0)).remove(&1));
-}
-
-#[bench]
-fn bench_remove_one(b: &mut Bencher) {
-    b.iter(|| black_box(TinyList::new_single(1)).remove(&1));
-}
diff --git a/compiler/rustc_data_structures/src/vec_linked_list.rs b/compiler/rustc_data_structures/src/vec_linked_list.rs
deleted file mode 100644
index fda72c9..0000000
--- a/compiler/rustc_data_structures/src/vec_linked_list.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-use rustc_index::{Idx, IndexVec};
-
-pub fn iter<Ls>(
-    first: Option<Ls::LinkIndex>,
-    links: &Ls,
-) -> impl Iterator<Item = Ls::LinkIndex> + '_
-where
-    Ls: Links,
-{
-    VecLinkedListIterator { links, current: first }
-}
-
-pub struct VecLinkedListIterator<Ls>
-where
-    Ls: Links,
-{
-    links: Ls,
-    current: Option<Ls::LinkIndex>,
-}
-
-impl<Ls> Iterator for VecLinkedListIterator<Ls>
-where
-    Ls: Links,
-{
-    type Item = Ls::LinkIndex;
-
-    fn next(&mut self) -> Option<Ls::LinkIndex> {
-        if let Some(c) = self.current {
-            self.current = <Ls as Links>::next(&self.links, c);
-            Some(c)
-        } else {
-            None
-        }
-    }
-}
-
-pub trait Links {
-    type LinkIndex: Copy;
-
-    fn next(links: &Self, index: Self::LinkIndex) -> Option<Self::LinkIndex>;
-}
-
-impl<Ls> Links for &Ls
-where
-    Ls: Links,
-{
-    type LinkIndex = Ls::LinkIndex;
-
-    fn next(links: &Self, index: Ls::LinkIndex) -> Option<Ls::LinkIndex> {
-        <Ls as Links>::next(links, index)
-    }
-}
-
-pub trait LinkElem {
-    type LinkIndex: Copy;
-
-    fn next(elem: &Self) -> Option<Self::LinkIndex>;
-}
-
-impl<L, E> Links for IndexVec<L, E>
-where
-    E: LinkElem<LinkIndex = L>,
-    L: Idx,
-{
-    type LinkIndex = L;
-
-    fn next(links: &Self, index: L) -> Option<L> {
-        <E as LinkElem>::next(&links[index])
-    }
-}
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index b2d38a0..ba6b9ef 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -11,6 +11,7 @@
 #![allow(internal_features)]
 #![feature(decl_macro)]
 #![feature(let_chains)]
+#![feature(panic_backtrace_config)]
 #![feature(panic_update_hook)]
 #![feature(result_flattening)]
 
@@ -1317,8 +1318,8 @@
     // by the user. Compiler developers and other rustc users can
     // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
     // (e.g. `RUST_BACKTRACE=1`)
-    if std::env::var_os("RUST_BACKTRACE").is_none() {
-        std::env::set_var("RUST_BACKTRACE", "full");
+    if env::var_os("RUST_BACKTRACE").is_none() {
+        panic::set_backtrace_style(panic::BacktraceStyle::Full);
     }
 
     let using_internal_features = Arc::new(std::sync::atomic::AtomicBool::default());
diff --git a/compiler/rustc_error_codes/src/error_codes/E0457.md b/compiler/rustc_error_codes/src/error_codes/E0457.md
index e2dbf53..47bff4b 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0457.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0457.md
@@ -1,4 +1,4 @@
-#### Note: this error code is no longer emitted by the compiler`
+#### Note: this error code is no longer emitted by the compiler
 
 Plugin `..` only found in rlib format, but must be available in dylib format.
 
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 1610135..18bb71bd 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -896,7 +896,7 @@
         style: SuggestionStyle,
     ) -> &mut Self {
         suggestion.sort_unstable();
-        suggestion.dedup();
+        suggestion.dedup_by(|(s1, m1), (s2, m2)| s1.source_equal(*s2) && m1 == m2);
 
         let parts = suggestion
             .into_iter()
diff --git a/compiler/rustc_errors/src/diagnostic_impls.rs b/compiler/rustc_errors/src/diagnostic_impls.rs
index 4696917..ee6df8e 100644
--- a/compiler/rustc_errors/src/diagnostic_impls.rs
+++ b/compiler/rustc_errors/src/diagnostic_impls.rs
@@ -94,6 +94,39 @@
     ErrCode,
 );
 
+impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::TraitRef<I> {
+    fn into_diag_arg(self) -> DiagArgValue {
+        self.to_string().into_diag_arg()
+    }
+}
+
+impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::ExistentialTraitRef<I> {
+    fn into_diag_arg(self) -> DiagArgValue {
+        self.to_string().into_diag_arg()
+    }
+}
+
+impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::UnevaluatedConst<I> {
+    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
+        format!("{self:?}").into_diag_arg()
+    }
+}
+
+impl<I: rustc_type_ir::Interner> IntoDiagArg for rustc_type_ir::FnSig<I> {
+    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
+        format!("{self:?}").into_diag_arg()
+    }
+}
+
+impl<I: rustc_type_ir::Interner, T> IntoDiagArg for rustc_type_ir::Binder<I, T>
+where
+    T: IntoDiagArg,
+{
+    fn into_diag_arg(self) -> DiagArgValue {
+        self.skip_binder().into_diag_arg()
+    }
+}
+
 into_diag_arg_for_number!(i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize);
 
 impl IntoDiagArg for bool {
@@ -258,6 +291,12 @@
     }
 }
 
+impl IntoDiagArg for hir::def::Namespace {
+    fn into_diag_arg(self) -> DiagArgValue {
+        DiagArgValue::Str(Cow::Borrowed(self.descr()))
+    }
+}
+
 #[derive(Clone)]
 pub struct DiagSymbolList(Vec<Symbol>);
 
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index b7aae2a..530b37a 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -10,6 +10,11 @@
 expand_attribute_single_word =
     attribute must only be a single word
 
+expand_attributes_on_expressions_experimental =
+    attributes on expressions are experimental
+    .help_outer_doc = `///` is used for outer documentation comments; for a plain comment, use `//`
+    .help_inner_doc = `//!` is used for inner documentation comments; for a plain comment, use `//` by removing the `!` or inserting a space in between them: `// !`
+
 expand_attributes_wrong_form =
     attribute must be of form: `attributes(foo, bar)`
 
@@ -30,6 +35,9 @@
     .label = duplicate binding
     .label2 = previous binding
 
+expand_empty_delegation_list =
+    empty list delegation is not supported
+
 expand_expected_paren_or_brace =
     expected `(` or `{"{"}`, found `{$token}`
 
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index 12868a6..91af875 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -1364,18 +1364,15 @@
                             };
 
                             if crate_matches {
-                                // FIXME: make this translatable
-                                #[allow(rustc::untranslatable_diagnostic)]
-                                sess.psess.buffer_lint_with_diagnostic(
-                                        PROC_MACRO_BACK_COMPAT,
-                                        item.ident.span,
-                                        ast::CRATE_NODE_ID,
-                                        "using an old version of `rental`",
-                                        BuiltinLintDiag::ProcMacroBackCompat(
-                                        "older versions of the `rental` crate will stop compiling in future versions of Rust; \
-                                        please update to `rental` v0.5.6, or switch to one of the `rental` alternatives".to_string()
-                                        )
-                                    );
+                                sess.psess.buffer_lint(
+                                    PROC_MACRO_BACK_COMPAT,
+                                    item.ident.span,
+                                    ast::CRATE_NODE_ID,
+                                    BuiltinLintDiag::ProcMacroBackCompat {
+                                        crate_name: "rental".to_string(),
+                                        fixed_version: "0.5.6".to_string(),
+                                    },
+                                );
                                 return true;
                             }
                         }
diff --git a/compiler/rustc_expand/src/config.rs b/compiler/rustc_expand/src/config.rs
index 897420a..badfa6d 100644
--- a/compiler/rustc_expand/src/config.rs
+++ b/compiler/rustc_expand/src/config.rs
@@ -14,6 +14,7 @@
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_feature::Features;
 use rustc_feature::{ACCEPTED_FEATURES, REMOVED_FEATURES, UNSTABLE_FEATURES};
+use rustc_lint_defs::BuiltinLintDiag;
 use rustc_parse::validate_attr;
 use rustc_session::parse::feature_err;
 use rustc_session::Session;
@@ -201,10 +202,17 @@
                     inner = self.configure_tokens(&inner);
                     Some(AttrTokenTree::Delimited(sp, spacing, delim, inner)).into_iter()
                 }
-                AttrTokenTree::Token(ref token, _)
-                    if let TokenKind::Interpolated(nt) = &token.kind =>
-                {
-                    panic!("Nonterminal should have been flattened at {:?}: {:?}", token.span, nt);
+                AttrTokenTree::Token(
+                    Token {
+                        kind:
+                            TokenKind::NtIdent(..)
+                            | TokenKind::NtLifetime(..)
+                            | TokenKind::Interpolated(..),
+                        ..
+                    },
+                    _,
+                ) => {
+                    panic!("Nonterminal should have been flattened: {:?}", tree);
                 }
                 AttrTokenTree::Token(token, spacing) => {
                     Some(AttrTokenTree::Token(token, spacing)).into_iter()
@@ -241,7 +249,6 @@
     /// Gives a compiler warning when the `cfg_attr` contains no attributes and
     /// is in the original source file. Gives a compiler error if the syntax of
     /// the attribute is incorrect.
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     pub(crate) fn expand_cfg_attr(&self, attr: &Attribute, recursive: bool) -> Vec<Attribute> {
         let Some((cfg_predicate, expanded_attrs)) =
             rustc_parse::parse_cfg_attr(attr, &self.sess.psess)
@@ -255,7 +262,7 @@
                 rustc_lint_defs::builtin::UNUSED_ATTRIBUTES,
                 attr.span,
                 ast::CRATE_NODE_ID,
-                "`#[cfg_attr]` does not expand to any attributes",
+                BuiltinLintDiag::CfgAttrNoAttributes,
             );
         }
 
@@ -276,7 +283,6 @@
         }
     }
 
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     fn expand_cfg_attr_item(
         &self,
         attr: &Attribute,
@@ -339,7 +345,7 @@
                 rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
                 attr.span,
                 ast::CRATE_NODE_ID,
-                "`crate_type` within an `#![cfg_attr] attribute is deprecated`",
+                BuiltinLintDiag::CrateTypeInCfgAttr,
             );
         }
         if attr.has_name(sym::crate_name) {
@@ -347,7 +353,7 @@
                 rustc_lint_defs::builtin::DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
                 attr.span,
                 ast::CRATE_NODE_ID,
-                "`crate_name` within an `#![cfg_attr] attribute is deprecated`",
+                BuiltinLintDiag::CrateNameInCfgAttr,
             );
         }
         attr
@@ -375,7 +381,6 @@
     }
 
     /// If attributes are not allowed on expressions, emit an error for `attr`
-    #[allow(rustc::untranslatable_diagnostic)] // FIXME: make this translatable
     #[instrument(level = "trace", skip(self))]
     pub(crate) fn maybe_emit_expr_attr_err(&self, attr: &Attribute) {
         if self.features.is_some_and(|features| !features.stmt_expr_attributes)
@@ -385,11 +390,15 @@
                 &self.sess,
                 sym::stmt_expr_attributes,
                 attr.span,
-                "attributes on expressions are experimental",
+                crate::fluent_generated::expand_attributes_on_expressions_experimental,
             );
 
             if attr.is_doc_comment() {
-                err.help("`///` is for documentation comments. For a plain comment, use `//`.");
+                err.help(if attr.style == AttrStyle::Outer {
+                    crate::fluent_generated::expand_help_outer_doc
+                } else {
+                    crate::fluent_generated::expand_help_inner_doc
+                });
             }
 
             err.emit();
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index b0563bf..a5fc9e9 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -433,3 +433,10 @@
     pub span: Span,
     pub token: Cow<'a, str>,
 }
+
+#[derive(Diagnostic)]
+#[diag(expand_empty_delegation_list)]
+pub(crate) struct EmptyDelegationList {
+    #[primary_span]
+    pub span: Span,
+}
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index f61cebc..d8f0f22 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -1,8 +1,8 @@
 use crate::base::*;
 use crate::config::StripUnconfigured;
 use crate::errors::{
-    IncompleteParse, RecursionLimitReached, RemoveExprNotSupported, RemoveNodeNotSupported,
-    UnsupportedKeyValue, WrongFragmentKind,
+    EmptyDelegationList, IncompleteParse, RecursionLimitReached, RemoveExprNotSupported,
+    RemoveNodeNotSupported, UnsupportedKeyValue, WrongFragmentKind,
 };
 use crate::mbe::diagnostics::annotate_err_with_kind;
 use crate::module::{mod_dir_path, parse_external_mod, DirOwnership, ParsedExternalMod};
@@ -1041,6 +1041,7 @@
 trait InvocationCollectorNode: HasAttrs + HasNodeId + Sized {
     type OutputTy = SmallVec<[Self; 1]>;
     type AttrsTy: Deref<Target = [ast::Attribute]> = ast::AttrVec;
+    type ItemKind = ItemKind;
     const KIND: AstFragmentKind;
     fn to_annotatable(self) -> Annotatable;
     fn fragment_to_output(fragment: AstFragment) -> Self::OutputTy;
@@ -1059,6 +1060,18 @@
     fn take_mac_call(self) -> (P<ast::MacCall>, Self::AttrsTy, AddSemicolon) {
         unreachable!()
     }
+    fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
+        None
+    }
+    fn delegation_item_kind(_deleg: Box<ast::Delegation>) -> Self::ItemKind {
+        unreachable!()
+    }
+    fn from_item(_item: ast::Item<Self::ItemKind>) -> Self {
+        unreachable!()
+    }
+    fn flatten_outputs(_outputs: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
+        unreachable!()
+    }
     fn pre_flat_map_node_collect_attr(_cfg: &StripUnconfigured<'_>, _attr: &ast::Attribute) {}
     fn post_flat_map_node_collect_bang(_output: &mut Self::OutputTy, _add_semicolon: AddSemicolon) {
     }
@@ -1106,6 +1119,21 @@
             _ => unreachable!(),
         }
     }
+    fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
+        match &self.kind {
+            ItemKind::DelegationMac(deleg) => Some((deleg, self)),
+            _ => None,
+        }
+    }
+    fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
+        ItemKind::Delegation(deleg)
+    }
+    fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
+        P(item)
+    }
+    fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
+        items.flatten().collect()
+    }
     fn wrap_flat_map_node_noop_flat_map(
         mut node: Self,
         collector: &mut InvocationCollector<'_, '_>,
@@ -1194,8 +1222,8 @@
                 match &ut.kind {
                     ast::UseTreeKind::Glob => {}
                     ast::UseTreeKind::Simple(_) => idents.push(ut.ident()),
-                    ast::UseTreeKind::Nested(nested) => {
-                        for (ut, _) in nested {
+                    ast::UseTreeKind::Nested { items, .. } => {
+                        for (ut, _) in items {
                             collect_use_tree_leaves(ut, idents);
                         }
                     }
@@ -1214,6 +1242,7 @@
 struct TraitItemTag;
 impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, TraitItemTag> {
     type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
+    type ItemKind = AssocItemKind;
     const KIND: AstFragmentKind = AstFragmentKind::TraitItems;
     fn to_annotatable(self) -> Annotatable {
         Annotatable::TraitItem(self.wrapped)
@@ -1234,11 +1263,27 @@
             _ => unreachable!(),
         }
     }
+    fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
+        match &self.wrapped.kind {
+            AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
+            _ => None,
+        }
+    }
+    fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
+        AssocItemKind::Delegation(deleg)
+    }
+    fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
+        AstNodeWrapper::new(P(item), TraitItemTag)
+    }
+    fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
+        items.flatten().collect()
+    }
 }
 
 struct ImplItemTag;
 impl InvocationCollectorNode for AstNodeWrapper<P<ast::AssocItem>, ImplItemTag> {
     type OutputTy = SmallVec<[P<ast::AssocItem>; 1]>;
+    type ItemKind = AssocItemKind;
     const KIND: AstFragmentKind = AstFragmentKind::ImplItems;
     fn to_annotatable(self) -> Annotatable {
         Annotatable::ImplItem(self.wrapped)
@@ -1259,6 +1304,21 @@
             _ => unreachable!(),
         }
     }
+    fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
+        match &self.wrapped.kind {
+            AssocItemKind::DelegationMac(deleg) => Some((deleg, &self.wrapped)),
+            _ => None,
+        }
+    }
+    fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
+        AssocItemKind::Delegation(deleg)
+    }
+    fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
+        AstNodeWrapper::new(P(item), ImplItemTag)
+    }
+    fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
+        items.flatten().collect()
+    }
 }
 
 impl InvocationCollectorNode for P<ast::ForeignItem> {
@@ -1420,6 +1480,24 @@
         };
         (mac, attrs, if add_semicolon { AddSemicolon::Yes } else { AddSemicolon::No })
     }
+    fn delegation_list(&self) -> Option<(&ast::DelegationMac, &ast::Item<Self::ItemKind>)> {
+        match &self.kind {
+            StmtKind::Item(item) => match &item.kind {
+                ItemKind::DelegationMac(deleg) => Some((deleg, item)),
+                _ => None,
+            },
+            _ => None,
+        }
+    }
+    fn delegation_item_kind(deleg: Box<ast::Delegation>) -> Self::ItemKind {
+        ItemKind::Delegation(deleg)
+    }
+    fn from_item(item: ast::Item<Self::ItemKind>) -> Self {
+        ast::Stmt { id: ast::DUMMY_NODE_ID, span: item.span, kind: StmtKind::Item(P(item)) }
+    }
+    fn flatten_outputs(items: impl Iterator<Item = Self::OutputTy>) -> Self::OutputTy {
+        items.flatten().collect()
+    }
     fn post_flat_map_node_collect_bang(stmts: &mut Self::OutputTy, add_semicolon: AddSemicolon) {
         // If this is a macro invocation with a semicolon, then apply that
         // semicolon to the final statement produced by expansion.
@@ -1721,11 +1799,10 @@
             }
 
             if attr.is_doc_comment() {
-                self.cx.sess.psess.buffer_lint_with_diagnostic(
+                self.cx.sess.psess.buffer_lint(
                     UNUSED_DOC_COMMENTS,
                     current_span,
                     self.cx.current_expansion.lint_node_id,
-                    "unused doc comment",
                     BuiltinLintDiag::UnusedDocComment(attr.span),
                 );
             } else if rustc_attr::is_builtin_attr(attr) {
@@ -1733,11 +1810,10 @@
                 // `#[cfg]` and `#[cfg_attr]` are special - they are
                 // eagerly evaluated.
                 if attr_name != sym::cfg && attr_name != sym::cfg_attr {
-                    self.cx.sess.psess.buffer_lint_with_diagnostic(
+                    self.cx.sess.psess.buffer_lint(
                         UNUSED_ATTRIBUTES,
                         attr.span,
                         self.cx.current_expansion.lint_node_id,
-                        format!("unused attribute `{attr_name}`"),
                         BuiltinLintDiag::UnusedBuiltinAttribute {
                             attr_name,
                             macro_name: pprust::path_to_string(&call.path),
@@ -1818,6 +1894,40 @@
                     Node::post_flat_map_node_collect_bang(&mut res, add_semicolon);
                     res
                 }
+                None if let Some((deleg, item)) = node.delegation_list() => {
+                    if deleg.suffixes.is_empty() {
+                        // Report an error for now, to avoid keeping stem for resolution and
+                        // stability checks.
+                        self.cx.dcx().emit_err(EmptyDelegationList { span: item.span });
+                    }
+
+                    Node::flatten_outputs(deleg.suffixes.iter().map(|&(ident, rename)| {
+                        let mut path = deleg.prefix.clone();
+                        path.segments.push(ast::PathSegment {
+                            ident,
+                            id: ast::DUMMY_NODE_ID,
+                            args: None,
+                        });
+
+                        let mut item = Node::from_item(ast::Item {
+                            attrs: item.attrs.clone(),
+                            id: ast::DUMMY_NODE_ID,
+                            span: ident.span,
+                            vis: item.vis.clone(),
+                            ident: rename.unwrap_or(ident),
+                            kind: Node::delegation_item_kind(Box::new(ast::Delegation {
+                                id: ast::DUMMY_NODE_ID,
+                                qself: deleg.qself.clone(),
+                                path,
+                                rename,
+                                body: deleg.body.clone(),
+                            })),
+                            tokens: None,
+                        });
+
+                        assign_id!(self, item.node_id_mut(), || item.noop_flat_map(self))
+                    }))
+                }
                 None => {
                     match Node::wrap_flat_map_node_noop_flat_map(node, self, |mut node, this| {
                         assign_id!(this, node.node_id_mut(), || node.noop_flat_map(this))
@@ -1866,6 +1976,7 @@
                         self.collect_bang(mac, Node::KIND).make_ast::<Node>()
                     })
                 }
+                None if node.delegation_list().is_some() => unreachable!(),
                 None => {
                     assign_id!(self, node.node_id_mut(), || node.noop_visit(self))
                 }
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 464361c..442fd65 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -55,7 +55,7 @@
 
     let span = token.span.substitute_dummy(sp);
 
-    let mut err = cx.dcx().struct_span_err(span, parse_failure_msg(&token));
+    let mut err = cx.dcx().struct_span_err(span, parse_failure_msg(&token, None));
     err.span_label(span, label);
     if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) {
         err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro");
@@ -73,12 +73,6 @@
         && (matches!(expected_token.kind, TokenKind::Interpolated(_))
             || matches!(token.kind, TokenKind::Interpolated(_)))
     {
-        if let TokenKind::Interpolated(node) = &expected_token.kind {
-            err.span_label(node.1, "");
-        }
-        if let TokenKind::Interpolated(node) = &token.kind {
-            err.span_label(node.1, "");
-        }
         err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens");
         err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information");
 
@@ -206,9 +200,17 @@
 }
 
 /// Currently used by macro_rules! compilation to extract a little information from the `Failure` case.
-pub struct FailureForwarder;
+pub struct FailureForwarder<'matcher> {
+    expected_token: Option<&'matcher Token>,
+}
 
-impl<'matcher> Tracker<'matcher> for FailureForwarder {
+impl<'matcher> FailureForwarder<'matcher> {
+    pub fn new() -> Self {
+        Self { expected_token: None }
+    }
+}
+
+impl<'matcher> Tracker<'matcher> for FailureForwarder<'matcher> {
     type Failure = (Token, usize, &'static str);
 
     fn build_failure(tok: Token, position: usize, msg: &'static str) -> Self::Failure {
@@ -218,6 +220,14 @@
     fn description() -> &'static str {
         "failure-forwarder"
     }
+
+    fn set_expected_token(&mut self, tok: &'matcher Token) {
+        self.expected_token = Some(tok);
+    }
+
+    fn get_expected_token(&self) -> Option<&'matcher Token> {
+        self.expected_token
+    }
 }
 
 pub(super) fn emit_frag_parse_err(
@@ -326,9 +336,19 @@
 
 /// Generates an appropriate parsing failure message. For EOF, this is "unexpected end...". For
 /// other tokens, this is "unexpected token...".
-pub(super) fn parse_failure_msg(tok: &Token) -> Cow<'static, str> {
-    match tok.kind {
-        token::Eof => Cow::from("unexpected end of macro invocation"),
-        _ => Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok))),
+pub(super) fn parse_failure_msg(tok: &Token, expected_token: Option<&Token>) -> Cow<'static, str> {
+    if let Some(expected_token) = expected_token {
+        Cow::from(format!(
+            "expected `{}`, found `{}`",
+            pprust::token_to_string(expected_token),
+            pprust::token_to_string(tok),
+        ))
+    } else {
+        match tok.kind {
+            token::Eof => Cow::from("unexpected end of macro invocation"),
+            _ => {
+                Cow::from(format!("no rules expected the token `{}`", pprust::token_to_string(tok)))
+            }
+        }
     }
 }
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index dce8e0c..72dbbde 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -110,7 +110,8 @@
 use rustc_ast::token::{Delimiter, IdentIsRaw, Token, TokenKind};
 use rustc_ast::{NodeId, DUMMY_NODE_ID};
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::{DiagMessage, MultiSpan};
+use rustc_errors::MultiSpan;
+use rustc_lint_defs::BuiltinLintDiag;
 use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER};
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::kw;
@@ -252,7 +253,7 @@
                 // 1. The meta-variable is already bound in the current LHS: This is an error.
                 let mut span = MultiSpan::from_span(span);
                 span.push_span_label(prev_info.span, "previous declaration");
-                buffer_lint(psess, span, node_id, "duplicate matcher binding");
+                buffer_lint(psess, span, node_id, BuiltinLintDiag::DuplicateMatcherBinding);
             } else if get_binder_info(macros, binders, name).is_none() {
                 // 2. The meta-variable is free: This is a binder.
                 binders.insert(name, BinderInfo { span, ops: ops.into() });
@@ -271,7 +272,7 @@
                     MISSING_FRAGMENT_SPECIFIER,
                     span,
                     node_id,
-                    "missing fragment specifier",
+                    BuiltinLintDiag::MissingFragmentSpecifier,
                 );
             }
             if !macros.is_empty() {
@@ -595,7 +596,7 @@
             return;
         }
     }
-    buffer_lint(psess, span.into(), node_id, format!("unknown macro variable `{name}`"));
+    buffer_lint(psess, span.into(), node_id, BuiltinLintDiag::UnknownMacroVariable(name));
 }
 
 /// Returns whether `binder_ops` is a prefix of `occurrence_ops`.
@@ -628,8 +629,7 @@
         if i >= occurrence_ops.len() {
             let mut span = MultiSpan::from_span(span);
             span.push_span_label(binder.span, "expected repetition");
-            let message = format!("variable '{name}' is still repeating at this depth");
-            buffer_lint(psess, span, node_id, message);
+            buffer_lint(psess, span, node_id, BuiltinLintDiag::MetaVariableStillRepeating(name));
             return;
         }
         let occurrence = &occurrence_ops[i];
@@ -637,21 +637,15 @@
             let mut span = MultiSpan::from_span(span);
             span.push_span_label(binder.span, "expected repetition");
             span.push_span_label(occurrence.span, "conflicting repetition");
-            let message = "meta-variable repeats with different Kleene operator";
-            buffer_lint(psess, span, node_id, message);
+            buffer_lint(psess, span, node_id, BuiltinLintDiag::MetaVariableWrongOperator);
             return;
         }
     }
 }
 
-fn buffer_lint(
-    psess: &ParseSess,
-    span: MultiSpan,
-    node_id: NodeId,
-    message: impl Into<DiagMessage>,
-) {
+fn buffer_lint(psess: &ParseSess, span: MultiSpan, node_id: NodeId, diag: BuiltinLintDiag) {
     // Macros loaded from other crates have dummy node ids.
     if node_id != DUMMY_NODE_ID {
-        psess.buffer_lint(META_VARIABLE_MISUSE, span, node_id, message);
+        psess.buffer_lint(META_VARIABLE_MISUSE, span, node_id, diag);
     }
 }
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index ffb50f4..2fbd09f 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -75,10 +75,9 @@
 
 use crate::mbe::{macro_rules::Tracker, KleeneOp, TokenTree};
 
-use rustc_ast::token::{self, DocComment, Nonterminal, NonterminalKind, Token};
+use rustc_ast::token::{self, DocComment, NonterminalKind, Token};
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::sync::Lrc;
 use rustc_errors::ErrorGuaranteed;
 use rustc_lint_defs::pluralize;
 use rustc_parse::parser::{ParseNtResult, Parser};
@@ -392,7 +391,7 @@
 #[derive(Debug, Clone)]
 pub(crate) enum NamedMatch {
     MatchedSeq(Vec<NamedMatch>),
-    MatchedSingle(ParseNtResult<Lrc<(Nonterminal, Span)>>),
+    MatchedSingle(ParseNtResult),
 }
 
 /// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison)
@@ -542,6 +541,8 @@
                         // The separator matches the current token. Advance past it.
                         mp.idx += 1;
                         self.next_mps.push(mp);
+                    } else {
+                        track.set_expected_token(separator);
                     }
                 }
                 &MatcherLoc::SequenceKleeneOpAfterSep { idx_first } => {
@@ -633,6 +634,7 @@
                 parser.approx_token_stream_pos(),
                 track,
             );
+
             if let Some(res) = res {
                 return res;
             }
@@ -686,11 +688,7 @@
                             }
                             Ok(nt) => nt,
                         };
-                        mp.push_match(
-                            next_metavar,
-                            seq_depth,
-                            MatchedSingle(nt.map_nt(|nt| (Lrc::new((nt, span))))),
-                        );
+                        mp.push_match(next_metavar, seq_depth, MatchedSingle(nt));
                         mp.idx += 1;
                     } else {
                         unreachable!()
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 470bde2..d99ecb6 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -79,11 +79,10 @@
         // but `m!()` is allowed in expression positions (cf. issue #34706).
         if kind == AstFragmentKind::Expr && parser.token == token::Semi {
             if is_local {
-                parser.psess.buffer_lint_with_diagnostic(
+                parser.psess.buffer_lint(
                     SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
                     parser.token.span,
                     lint_node_id,
-                    "trailing semicolon in macro used in expression position",
                     BuiltinLintDiag::TrailingMacro(is_trailing_mac, macro_ident),
                 );
             }
@@ -167,6 +166,11 @@
     fn recovery() -> Recovery {
         Recovery::Forbidden
     }
+
+    fn set_expected_token(&mut self, _tok: &'matcher Token) {}
+    fn get_expected_token(&self) -> Option<&'matcher Token> {
+        None
+    }
 }
 
 /// A noop tracker that is used in the hot path of the expansion, has zero overhead thanks to
@@ -447,16 +451,14 @@
                 // For this we need to reclone the macro body as the previous parser consumed it.
                 let retry_parser = create_parser();
 
-                let parse_result = tt_parser.parse_tt(
-                    &mut Cow::Owned(retry_parser),
-                    &argument_gram,
-                    &mut diagnostics::FailureForwarder,
-                );
+                let mut track = diagnostics::FailureForwarder::new();
+                let parse_result =
+                    tt_parser.parse_tt(&mut Cow::Owned(retry_parser), &argument_gram, &mut track);
                 let Failure((token, _, msg)) = parse_result else {
                     unreachable!("matcher returned something other than Failure after retry");
                 };
 
-                let s = parse_failure_msg(&token);
+                let s = parse_failure_msg(&token, track.get_expected_token());
                 let sp = token.span.substitute_dummy(def.span);
                 let mut err = sess.dcx().struct_span_err(sp, s);
                 err.span_label(sp, msg);
@@ -1151,11 +1153,10 @@
                             name,
                             Some(NonterminalKind::PatParam { inferred: false }),
                         ));
-                        sess.psess.buffer_lint_with_diagnostic(
+                        sess.psess.buffer_lint(
                             RUST_2021_INCOMPATIBLE_OR_PATTERNS,
                             span,
                             ast::CRATE_NODE_ID,
-                            "the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro",
                             BuiltinLintDiag::OrPatternsBackCompat(span, suggestion),
                         );
                     }
@@ -1290,7 +1291,7 @@
                 // maintain
                 IsInFollow::Yes
             }
-            NonterminalKind::Stmt | NonterminalKind::Expr => {
+            NonterminalKind::Stmt | NonterminalKind::Expr | NonterminalKind::Expr2021 => {
                 const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
                 match tok {
                     TokenTree::Token(token) => match token.kind {
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index 8239cfd..128e9f4 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -23,7 +23,7 @@
 
     /// The length of the repetition at a particular depth, where 0 is the inner-most
     /// repetition. The `usize` is the depth.
-    Length(usize),
+    Len(usize),
 }
 
 impl MetaVarExpr {
@@ -48,13 +48,13 @@
                 MetaVarExpr::Ignore(parse_ident(&mut iter, psess, ident.span)?)
             }
             "index" => MetaVarExpr::Index(parse_depth(&mut iter, psess, ident.span)?),
-            "length" => MetaVarExpr::Length(parse_depth(&mut iter, psess, ident.span)?),
+            "len" => MetaVarExpr::Len(parse_depth(&mut iter, psess, ident.span)?),
             _ => {
                 let err_msg = "unrecognized meta-variable expression";
                 let mut err = psess.dcx.struct_span_err(ident.span, err_msg);
                 err.span_suggestion(
                     ident.span,
-                    "supported expressions are count, ignore, index and length",
+                    "supported expressions are count, ignore, index and len",
                     "",
                     Applicability::MachineApplicable,
                 );
@@ -68,7 +68,7 @@
     pub(crate) fn ident(&self) -> Option<Ident> {
         match *self {
             MetaVarExpr::Count(ident, _) | MetaVarExpr::Ignore(ident) => Some(ident),
-            MetaVarExpr::Index(..) | MetaVarExpr::Length(..) => None,
+            MetaVarExpr::Index(..) | MetaVarExpr::Len(..) => None,
         }
     }
 }
@@ -111,7 +111,7 @@
     Ok(MetaVarExpr::Count(ident, depth))
 }
 
-/// Parses the depth used by index(depth) and length(depth).
+/// Parses the depth used by index(depth) and len(depth).
 fn parse_depth<'psess>(
     iter: &mut RefTokenTreeCursor<'_>,
     psess: &'psess ParseSess,
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index 06c1612..d3ea48e 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -16,6 +16,10 @@
 const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
                                         `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
                                         `literal`, `path`, `meta`, `tt`, `item` and `vis`";
+const VALID_FRAGMENT_NAMES_MSG_2021: &str = "valid fragment specifiers are \
+                                             `ident`, `block`, `stmt`, `expr`, `expr_2021`, `pat`, \
+                                             `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, \
+                                             `item` and `vis`";
 
 /// Takes a `tokenstream::TokenStream` and returns a `Vec<self::TokenTree>`. Specifically, this
 /// takes a generic `TokenStream`, such as is used in the rest of the compiler, and returns a
@@ -63,35 +67,60 @@
                             Some(tokenstream::TokenTree::Token(token, _)) => match token.ident() {
                                 Some((fragment, _)) => {
                                     let span = token.span.with_lo(start_sp.lo());
-
+                                    let edition = || {
+                                        // FIXME(#85708) - once we properly decode a foreign
+                                        // crate's `SyntaxContext::root`, then we can replace
+                                        // this with just `span.edition()`. A
+                                        // `SyntaxContext::root()` from the current crate will
+                                        // have the edition of the current crate, and a
+                                        // `SyntaxContext::root()` from a foreign crate will
+                                        // have the edition of that crate (which we manually
+                                        // retrieve via the `edition` parameter).
+                                        if !span.from_expansion() {
+                                            edition
+                                        } else {
+                                            span.edition()
+                                        }
+                                    };
                                     let kind =
-                                        token::NonterminalKind::from_symbol(fragment.name, || {
-                                            // FIXME(#85708) - once we properly decode a foreign
-                                            // crate's `SyntaxContext::root`, then we can replace
-                                            // this with just `span.edition()`. A
-                                            // `SyntaxContext::root()` from the current crate will
-                                            // have the edition of the current crate, and a
-                                            // `SyntaxContext::root()` from a foreign crate will
-                                            // have the edition of that crate (which we manually
-                                            // retrieve via the `edition` parameter).
-                                            if !span.from_expansion() {
-                                                edition
-                                            } else {
-                                                span.edition()
-                                            }
-                                        })
-                                        .unwrap_or_else(
-                                            || {
+                                        token::NonterminalKind::from_symbol(fragment.name, edition)
+                                            .unwrap_or_else(|| {
+                                                let help = match fragment.name {
+                                                    sym::expr_2021 => {
+                                                        format!(
+                                                            "fragment specifier `expr_2021` \
+                                                             requires Rust 2021 or later\n\
+                                                             {VALID_FRAGMENT_NAMES_MSG}"
+                                                        )
+                                                    }
+                                                    _ if edition().at_least_rust_2021()
+                                                        && features
+                                                            .expr_fragment_specifier_2024 =>
+                                                    {
+                                                        VALID_FRAGMENT_NAMES_MSG_2021.into()
+                                                    }
+                                                    _ => VALID_FRAGMENT_NAMES_MSG.into(),
+                                                };
                                                 sess.dcx().emit_err(
                                                     errors::InvalidFragmentSpecifier {
                                                         span,
                                                         fragment,
-                                                        help: VALID_FRAGMENT_NAMES_MSG.into(),
+                                                        help,
                                                     },
                                                 );
                                                 token::NonterminalKind::Ident
-                                            },
-                                        );
+                                            });
+                                    if kind == token::NonterminalKind::Expr2021
+                                        && !features.expr_fragment_specifier_2024
+                                    {
+                                        rustc_session::parse::feature_err(
+                                            sess,
+                                            sym::expr_fragment_specifier_2024,
+                                            span,
+                                            "fragment specifier `expr_2021` is unstable",
+                                        )
+                                        .emit();
+                                    }
                                     result.push(TokenTree::MetaVarDecl(span, ident, Some(kind)));
                                     continue;
                                 }
@@ -357,7 +386,7 @@
 
 // `$$` or a meta-variable is the lhs of a macro but shouldn't.
 //
-// For example, `macro_rules! foo { ( ${length()} ) => {} }`
+// For example, `macro_rules! foo { ( ${len()} ) => {} }`
 fn span_dollar_dollar_or_metavar_in_the_lhs_err(sess: &Session, token: &Token) {
     sess.dcx()
         .span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token)));
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 011aa95..3901b82 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -261,6 +261,16 @@
                             // without wrapping them into groups.
                             maybe_use_metavar_location(cx, &stack, sp, tt, &mut marker)
                         }
+                        MatchedSingle(ParseNtResult::Ident(ident, is_raw)) => {
+                            marker.visit_span(&mut sp);
+                            let kind = token::NtIdent(*ident, *is_raw);
+                            TokenTree::token_alone(kind, sp)
+                        }
+                        MatchedSingle(ParseNtResult::Lifetime(ident)) => {
+                            marker.visit_span(&mut sp);
+                            let kind = token::NtLifetime(*ident);
+                            TokenTree::token_alone(kind, sp)
+                        }
                         MatchedSingle(ParseNtResult::Nt(nt)) => {
                             // Other variables are emitted into the output stream as groups with
                             // `Delimiter::Invisible` to maintain parsing priorities.
@@ -675,14 +685,14 @@
             }
             None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "index")),
         },
-        MetaVarExpr::Length(depth) => match repeats.iter().nth_back(depth) {
+        MetaVarExpr::Len(depth) => match repeats.iter().nth_back(depth) {
             Some((_, length)) => {
                 result.push(TokenTree::token_alone(
                     TokenKind::lit(token::Integer, sym::integer(*length), None),
                     visited_span(),
                 ));
             }
-            None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "length")),
+            None => return Err(out_of_bounds_err(cx, repeats.len(), sp.entire(), "len")),
         },
     }
     Ok(())
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 7026425..e21f041 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -174,7 +174,10 @@
         }]),
         AstFragmentKind::Variants => AstFragment::Variants(smallvec![ast::Variant {
             attrs: Default::default(),
-            data: ast::VariantData::Struct { fields: Default::default(), recovered: false },
+            data: ast::VariantData::Struct {
+                fields: Default::default(),
+                recovered: ast::Recovered::No
+            },
             disr_expr: None,
             id,
             ident,
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 4b5c148..530059e 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -127,7 +127,7 @@
                 Annotatable::Stmt(stmt) => token::NtStmt(stmt),
                 _ => unreachable!(),
             };
-            TokenStream::token_alone(token::Interpolated(Lrc::new((nt, span))), DUMMY_SP)
+            TokenStream::token_alone(token::Interpolated(Lrc::new(nt)), DUMMY_SP)
         } else {
             item.to_tokens()
         };
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 5a66b0f..1f3547c 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -220,6 +220,12 @@
                 Ident(sym, is_raw) => {
                     trees.push(TokenTree::Ident(Ident { sym, is_raw: is_raw.into(), span }))
                 }
+                NtIdent(ident, is_raw) => trees.push(TokenTree::Ident(Ident {
+                    sym: ident.name,
+                    is_raw: is_raw.into(),
+                    span: ident.span,
+                })),
+
                 Lifetime(name) => {
                     let ident = symbol::Ident::new(name, span).without_first_quote();
                     trees.extend([
@@ -227,6 +233,15 @@
                         TokenTree::Ident(Ident { sym: ident.name, is_raw: false, span }),
                     ]);
                 }
+                NtLifetime(ident) => {
+                    let stream = TokenStream::token_alone(token::Lifetime(ident.name), ident.span);
+                    trees.push(TokenTree::Group(Group {
+                        delimiter: pm::Delimiter::None,
+                        stream: Some(stream),
+                        span: DelimSpan::from_single(span),
+                    }))
+                }
+
                 Literal(token::Lit { kind, symbol, suffix }) => {
                     trees.push(TokenTree::Literal(self::Literal {
                         kind: FromInternal::from_internal(kind),
@@ -259,23 +274,15 @@
                     }));
                 }
 
-                Interpolated(ref nt) if let NtIdent(ident, is_raw) = &nt.0 => {
-                    trees.push(TokenTree::Ident(Ident {
-                        sym: ident.name,
-                        is_raw: matches!(is_raw, IdentIsRaw::Yes),
-                        span: ident.span,
-                    }))
-                }
-
                 Interpolated(nt) => {
-                    let stream = TokenStream::from_nonterminal_ast(&nt.0);
+                    let stream = TokenStream::from_nonterminal_ast(&nt);
                     // A hack used to pass AST fragments to attribute and derive
                     // macros as a single nonterminal token instead of a token
                     // stream. Such token needs to be "unwrapped" and not
                     // represented as a delimited group.
                     // FIXME: It needs to be removed, but there are some
                     // compatibility issues (see #73345).
-                    if crate::base::nt_pretty_printing_compatibility_hack(&nt.0, rustc.ecx.sess) {
+                    if crate::base::nt_pretty_printing_compatibility_hack(&nt, rustc.ecx.sess) {
                         trees.extend(Self::from_internal((stream, rustc)));
                     } else {
                         trees.push(TokenTree::Group(Group {
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index dbb88e4..0b4a871 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -515,12 +515,6 @@
         EncodeCrossCrate::Yes, experimental!(deprecated_safe),
     ),
 
-    // RFC 2397
-    gated!(
-        do_not_recommend, Normal, template!(Word), WarnFollowing,
-        EncodeCrossCrate::Yes, experimental!(do_not_recommend)
-    ),
-
     // `#[cfi_encoding = ""]`
     gated!(
         cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding,
@@ -899,10 +893,11 @@
         "the `#[rustc_main]` attribute is used internally to specify test entry point function",
     ),
     rustc_attr!(
-        rustc_skip_array_during_method_dispatch, Normal, template!(Word),
-        WarnFollowing, EncodeCrossCrate::No,
-        "the `#[rustc_skip_array_during_method_dispatch]` attribute is used to exclude a trait \
-        from method dispatch when the receiver is an array, for compatibility in editions < 2021."
+        rustc_skip_during_method_dispatch, Normal, template!(List: "array, boxed_slice"), WarnFollowing,
+        EncodeCrossCrate::No,
+        "the `#[rustc_skip_during_method_dispatch]` attribute is used to exclude a trait \
+        from method dispatch when the receiver is of the following type, for compatibility in \
+        editions < 2021 (array) or editions < 2024 (boxed_slice)."
     ),
     rustc_attr!(
         rustc_must_implement_one_of, Normal, template!(List: "function1, function2, ..."),
diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs
index 60b386a..dc4807b 100644
--- a/compiler/rustc_feature/src/unstable.rs
+++ b/compiler/rustc_feature/src/unstable.rs
@@ -458,6 +458,8 @@
     (unstable, exhaustive_patterns, "1.13.0", Some(51085)),
     /// Allows explicit tail calls via `become` expression.
     (incomplete, explicit_tail_calls, "1.72.0", Some(112788)),
+    /// Uses 2024 rules for matching `expr` fragments in macros. Also enables `expr_2021` fragment.
+    (incomplete, expr_fragment_specifier_2024, "CURRENT_RUSTC_VERSION", Some(123742)),
     /// Allows using `efiapi`, `sysv64` and `win64` as calling convention
     /// for functions with varargs.
     (unstable, extended_varargs_abi_support, "1.65.0", Some(100189)),
@@ -487,6 +489,8 @@
     (incomplete, generic_const_exprs, "1.56.0", Some(76560)),
     /// Allows generic parameters and where-clauses on free & associated const items.
     (incomplete, generic_const_items, "1.73.0", Some(113521)),
+    /// Allows registering static items globally, possibly across crates, to iterate over at runtime.
+    (unstable, global_registration, "CURRENT_RUSTC_VERSION", Some(125119)),
     /// Allows using `..=X` as a patterns in slices.
     (unstable, half_open_range_patterns_in_slices, "1.66.0", Some(67264)),
     /// Allows `if let` guard in match arms.
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 244c479..2f4dcdb 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1308,9 +1308,9 @@
     pub pat: &'hir Pat<'hir>,
     pub ty: Option<&'hir Ty<'hir>>,
     pub init: &'hir Expr<'hir>,
-    /// `Some` when this let expressions is not in a syntanctically valid location.
+    /// `Recovered::Yes` when this let expressions is not in a syntanctically valid location.
     /// Used to prevent building MIR in such situations.
-    pub is_recovered: Option<ErrorGuaranteed>,
+    pub recovered: ast::Recovered,
 }
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
@@ -2604,7 +2604,7 @@
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub struct BareFnTy<'hir> {
-    pub unsafety: Unsafety,
+    pub safety: Safety,
     pub abi: Abi,
     pub generic_params: &'hir [GenericParam<'hir>],
     pub decl: &'hir FnDecl<'hir>,
@@ -2631,7 +2631,7 @@
     /// lowered as an associated type.
     pub in_trait: bool,
     /// List of arguments captured via `impl use<'a, P, ...> Trait` syntax.
-    pub precise_capturing_args: Option<&'hir [PreciseCapturingArg<'hir>]>,
+    pub precise_capturing_args: Option<(&'hir [PreciseCapturingArg<'hir>], Span)>,
 }
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
@@ -2641,6 +2641,15 @@
     Param(PreciseCapturingNonLifetimeArg),
 }
 
+impl PreciseCapturingArg<'_> {
+    pub fn hir_id(self) -> HirId {
+        match self {
+            PreciseCapturingArg::Lifetime(lt) => lt.hir_id,
+            PreciseCapturingArg::Param(param) => param.hir_id,
+        }
+    }
+}
+
 /// We need to have a [`Node`] for the [`HirId`] that we attach the type/const param
 /// resolution to. Lifetimes don't have this problem, and for them, it's actually
 /// kind of detrimental to use a custom node type versus just using [`Lifetime`],
@@ -3030,11 +3039,7 @@
     /// A struct variant.
     ///
     /// E.g., `Bar { .. }` as in `enum Foo { Bar { .. } }`.
-    Struct {
-        fields: &'hir [FieldDef<'hir>],
-        // FIXME: investigate making this a `Option<ErrorGuaranteed>`
-        recovered: bool,
-    },
+    Struct { fields: &'hir [FieldDef<'hir>], recovered: ast::Recovered },
     /// A tuple variant.
     ///
     /// E.g., `Bar(..)` as in `enum Foo { Bar(..) }`.
@@ -3167,9 +3172,9 @@
             ItemKind::Union(data, gen), (data, gen);
 
         expect_trait,
-            (IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
-            ItemKind::Trait(is_auto, unsafety, gen, bounds, items),
-            (*is_auto, *unsafety, gen, bounds, items);
+            (IsAuto, Safety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
+            ItemKind::Trait(is_auto, safety, gen, bounds, items),
+            (*is_auto, *safety, gen, bounds, items);
 
         expect_trait_alias, (&'hir Generics<'hir>, GenericBounds<'hir>),
             ItemKind::TraitAlias(gen, bounds), (gen, bounds);
@@ -3180,25 +3185,25 @@
 
 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 #[derive(Encodable, Decodable, HashStable_Generic)]
-pub enum Unsafety {
+pub enum Safety {
     Unsafe,
-    Normal,
+    Safe,
 }
 
-impl Unsafety {
-    pub fn prefix_str(&self) -> &'static str {
+impl Safety {
+    pub fn prefix_str(self) -> &'static str {
         match self {
             Self::Unsafe => "unsafe ",
-            Self::Normal => "",
+            Self::Safe => "",
         }
     }
 }
 
-impl fmt::Display for Unsafety {
+impl fmt::Display for Safety {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.write_str(match *self {
             Self::Unsafe => "unsafe",
-            Self::Normal => "normal",
+            Self::Safe => "safe",
         })
     }
 }
@@ -3220,7 +3225,7 @@
 
 #[derive(Copy, Clone, Debug, HashStable_Generic)]
 pub struct FnHeader {
-    pub unsafety: Unsafety,
+    pub safety: Safety,
     pub constness: Constness,
     pub asyncness: IsAsync,
     pub abi: Abi,
@@ -3236,7 +3241,7 @@
     }
 
     pub fn is_unsafe(&self) -> bool {
-        matches!(&self.unsafety, Unsafety::Unsafe)
+        matches!(&self.safety, Safety::Unsafe)
     }
 }
 
@@ -3279,7 +3284,7 @@
     /// A union definition, e.g., `union Foo<A, B> {x: A, y: B}`.
     Union(VariantData<'hir>, &'hir Generics<'hir>),
     /// A trait definition.
-    Trait(IsAuto, Unsafety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
+    Trait(IsAuto, Safety, &'hir Generics<'hir>, GenericBounds<'hir>, &'hir [TraitItemRef]),
     /// A trait alias.
     TraitAlias(&'hir Generics<'hir>, GenericBounds<'hir>),
 
@@ -3289,7 +3294,7 @@
 
 #[derive(Debug, Clone, Copy, HashStable_Generic)]
 pub struct Impl<'hir> {
-    pub unsafety: Unsafety,
+    pub safety: Safety,
     pub polarity: ImplPolarity,
     pub defaultness: Defaultness,
     // We do not put a `Span` in `Defaultness` because it breaks foreign crate metadata
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index fa89a4a..b202ea8 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -533,7 +533,7 @@
             try_visit!(visitor.visit_id(item.hir_id()));
             try_visit!(walk_generics(visitor, generics));
             walk_list!(visitor, visit_param_bound, bounds);
-            if let Some(precise_capturing_args) = precise_capturing_args {
+            if let Some((precise_capturing_args, _)) = precise_capturing_args {
                 for arg in precise_capturing_args {
                     try_visit!(visitor.visit_precise_capturing_arg(arg));
                 }
@@ -545,7 +545,7 @@
             try_visit!(visitor.visit_enum_def(enum_definition, item.hir_id()));
         }
         ItemKind::Impl(Impl {
-            unsafety: _,
+            safety: _,
             defaultness: _,
             polarity: _,
             defaultness_span: _,
@@ -768,7 +768,7 @@
         ExprKind::DropTemps(ref subexpression) => {
             try_visit!(visitor.visit_expr(subexpression));
         }
-        ExprKind::Let(LetExpr { span: _, pat, ty, init, is_recovered: _ }) => {
+        ExprKind::Let(LetExpr { span: _, pat, ty, init, recovered: _ }) => {
             // match the visit order in walk_local
             try_visit!(visitor.visit_expr(init));
             try_visit!(visitor.visit_pat(pat));
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index e870a04..c4be67c 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -55,21 +55,27 @@
     (
         $( $(#[$attr:meta])* $variant:ident, $module:ident :: $name:ident, $method:ident, $target:expr, $generics:expr; )*
     ) => {
-
-        rustc_data_structures::enum_from_u32! {
-            /// A representation of all the valid lang items in Rust.
-            #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
-            pub enum LangItem {
-                $(
-                    #[doc = concat!("The `", stringify!($name), "` lang item.")]
-                    ///
-                    $(#[$attr])*
-                    $variant,
-                )*
-            }
+        /// A representation of all the valid lang items in Rust.
+        #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
+        pub enum LangItem {
+            $(
+                #[doc = concat!("The `", stringify!($name), "` lang item.")]
+                $(#[$attr])*
+                $variant,
+            )*
         }
 
         impl LangItem {
+            fn from_u32(u: u32) -> Option<LangItem> {
+                // This implementation is clumsy, but makes no assumptions
+                // about how discriminant tags are allocated within the
+                // range `0 .. std::mem::variant_count::<LangItem>()`.
+                $(if u == LangItem::$variant as u32 {
+                    return Some(LangItem::$variant)
+                })*
+                None
+            }
+
             /// Returns the `name` symbol in `#[lang = "$name"]`.
             /// For example, [`LangItem::PartialEq`]`.name()`
             /// would result in [`sym::eq`] since it is `#[lang = "eq"]`.
@@ -147,7 +153,7 @@
     Clone,                   sym::clone,               clone_trait,                Target::Trait,          GenericRequirement::None;
     Sync,                    sym::sync,                sync_trait,                 Target::Trait,          GenericRequirement::Exact(0);
     DiscriminantKind,        sym::discriminant_kind,   discriminant_kind_trait,    Target::Trait,          GenericRequirement::None;
-    /// The associated item of the [`DiscriminantKind`] trait.
+    /// The associated item of the `DiscriminantKind` trait.
     Discriminant,            sym::discriminant_type,   discriminant_type,          Target::AssocTy,        GenericRequirement::None;
 
     PointeeTrait,            sym::pointee_trait,       pointee_trait,              Target::Trait,          GenericRequirement::None;
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index f101c59..2bf14a2 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -68,28 +68,27 @@
         }
 
         // Otherwise, deref if type is derefable:
-        let (kind, new_ty) = if let Some(ty::TypeAndMut { ty, .. }) =
-            self.state.cur_ty.builtin_deref(self.include_raw_pointers)
-        {
-            debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty));
-            // NOTE: we may still need to normalize the built-in deref in case
-            // we have some type like `&<Ty as Trait>::Assoc`, since users of
-            // autoderef expect this type to have been structurally normalized.
-            if self.infcx.next_trait_solver()
-                && let ty::Alias(..) = ty.kind()
-            {
-                let (normalized_ty, obligations) = self.structurally_normalize(ty)?;
-                self.state.obligations.extend(obligations);
-                (AutoderefKind::Builtin, normalized_ty)
+        let (kind, new_ty) =
+            if let Some(ty) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
+                debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty));
+                // NOTE: we may still need to normalize the built-in deref in case
+                // we have some type like `&<Ty as Trait>::Assoc`, since users of
+                // autoderef expect this type to have been structurally normalized.
+                if self.infcx.next_trait_solver()
+                    && let ty::Alias(..) = ty.kind()
+                {
+                    let (normalized_ty, obligations) = self.structurally_normalize(ty)?;
+                    self.state.obligations.extend(obligations);
+                    (AutoderefKind::Builtin, normalized_ty)
+                } else {
+                    (AutoderefKind::Builtin, ty)
+                }
+            } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
+                // The overloaded deref check already normalizes the pointee type.
+                (AutoderefKind::Overloaded, ty)
             } else {
-                (AutoderefKind::Builtin, ty)
-            }
-        } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
-            // The overloaded deref check already normalizes the pointee type.
-            (AutoderefKind::Overloaded, ty)
-        } else {
-            return None;
-        };
+                return None;
+            };
 
         self.state.steps.push((self.state.cur_ty, kind));
         debug!(
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 5562b81..38ecd7d 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -2,7 +2,7 @@
 //! [`rustc_middle::ty`] form.
 
 use rustc_hir::LangItem;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
 use rustc_span::Span;
 
 /// Collects together a list of type bounds. These lists of bounds occur in many places
@@ -34,7 +34,7 @@
         span: Span,
     ) {
         self.clauses
-            .push((region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)).to_predicate(tcx), span));
+            .push((region.map_bound(|p| ty::ClauseKind::TypeOutlives(p)).upcast(tcx), span));
     }
 
     pub fn push_trait_bound(
@@ -49,7 +49,7 @@
                 .map_bound(|trait_ref| {
                     ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity })
                 })
-                .to_predicate(tcx),
+                .upcast(tcx),
             span,
         );
         // FIXME(-Znext-solver): We can likely remove this hack once the new trait solver lands.
@@ -67,7 +67,7 @@
         span: Span,
     ) {
         self.clauses.push((
-            projection.map_bound(|proj| ty::ClauseKind::Projection(proj)).to_predicate(tcx),
+            projection.map_bound(|proj| ty::ClauseKind::Projection(proj)).upcast(tcx),
             span,
         ));
     }
@@ -76,7 +76,7 @@
         let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span));
         let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]);
         // Preferable to put this obligation first, since we report better errors for sized ambiguity.
-        self.clauses.insert(0, (trait_ref.to_predicate(tcx), span));
+        self.clauses.insert(0, (trait_ref.upcast(tcx), span));
     }
 
     pub fn clauses(&self) -> impl Iterator<Item = (ty::Clause<'tcx>, Span)> + '_ {
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 32e1b19..b5c0675 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -14,6 +14,7 @@
 use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
 use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
 use rustc_middle::middle::stability::EvalResult;
+use rustc_middle::span_bug;
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
 use rustc_middle::ty::util::{Discr, InspectCoroutineFields, IntTypeExt};
@@ -485,7 +486,7 @@
 fn check_opaque_precise_captures<'tcx>(tcx: TyCtxt<'tcx>, opaque_def_id: LocalDefId) {
     let hir::OpaqueTy { precise_capturing_args, .. } =
         *tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty();
-    let Some(precise_capturing_args) = precise_capturing_args else {
+    let Some((precise_capturing_args, _)) = precise_capturing_args else {
         // No precise capturing args; nothing to validate
         return;
     };
@@ -561,7 +562,7 @@
         let generics = tcx.generics_of(generics);
         def_id = generics.parent;
 
-        for param in &generics.params {
+        for param in &generics.own_params {
             if expected_captures.contains(&param.def_id) {
                 assert_eq!(
                     variances[param.index as usize],
@@ -778,7 +779,7 @@
                         let def_id = item.id.owner_id.def_id;
                         let generics = tcx.generics_of(def_id);
                         let own_counts = generics.own_counts();
-                        if generics.params.len() - own_counts.lifetimes != 0 {
+                        if generics.own_params.len() - own_counts.lifetimes != 0 {
                             let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts)
                             {
                                 (_, 0) => ("type", "types", Some("u32")),
@@ -1544,7 +1545,7 @@
             .collect::<FxIndexMap<_, _>>()
     });
 
-    let mut params_used = BitSet::new_empty(generics.params.len());
+    let mut params_used = BitSet::new_empty(generics.own_params.len());
     for leaf in ty.walk() {
         if let GenericArgKind::Type(leaf_ty) = leaf.unpack()
             && let ty::Param(param) = leaf_ty.kind()
@@ -1554,7 +1555,7 @@
         }
     }
 
-    for param in &generics.params {
+    for param in &generics.own_params {
         if !params_used.contains(param.index)
             && let ty::GenericParamDefKind::Type { .. } = param.kind
         {
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index d275908..44bf8fd 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -9,17 +9,17 @@
 use rustc_hir::intravisit;
 use rustc_hir::{GenericParamKind, ImplItemKind};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::{util, FulfillmentError};
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::BottomUpFolder;
 use rustc_middle::ty::util::ExplicitSelf;
-use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::Upcast;
 use rustc_middle::ty::{
     self, GenericArgs, Ty, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
 };
 use rustc_middle::ty::{GenericParamDefKind, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
@@ -176,7 +176,7 @@
     let cause = ObligationCause::new(
         impl_m_span,
         impl_m_def_id,
-        ObligationCauseCode::CompareImplItemObligation {
+        ObligationCauseCode::CompareImplItem {
             impl_item_def_id: impl_m_def_id,
             trait_item_def_id: trait_m.def_id,
             kind: impl_m.kind,
@@ -237,7 +237,7 @@
         let cause = ObligationCause::new(
             span,
             impl_m_def_id,
-            ObligationCauseCode::CompareImplItemObligation {
+            ObligationCauseCode::CompareImplItem {
                 impl_item_def_id: impl_m_def_id,
                 trait_item_def_id: trait_m.def_id,
                 kind: impl_m.kind,
@@ -465,7 +465,7 @@
     let cause = ObligationCause::new(
         return_span,
         impl_m_def_id,
-        ObligationCauseCode::CompareImplItemObligation {
+        ObligationCauseCode::CompareImplItem {
             impl_item_def_id: impl_m_def_id,
             trait_item_def_id: trait_m.def_id,
             kind: impl_m.kind,
@@ -716,7 +716,7 @@
                 // since we previously enforce that the trait method and impl method have the
                 // same generics.
                 let num_trait_args = trait_to_impl_args.len();
-                let num_impl_args = tcx.generics_of(impl_m.container_id(tcx)).params.len();
+                let num_impl_args = tcx.generics_of(impl_m.container_id(tcx)).own_params.len();
                 let ty = match ty.try_fold_with(&mut RemapHiddenTyRegions {
                     tcx,
                     map,
@@ -800,10 +800,7 @@
                 bug!("FIXME(RPITIT): error here");
             }
             // Replace with infer var
-            let infer_ty = self
-                .ocx
-                .infcx
-                .next_ty_var(TypeVariableOrigin { span: self.span, param_def_id: None });
+            let infer_ty = self.ocx.infcx.next_ty_var(self.span);
             self.types.insert(proj.def_id, (infer_ty, proj.args));
             // Recurse into bounds
             for (pred, pred_span) in self
@@ -823,7 +820,7 @@
                     ObligationCause::new(
                         self.span,
                         self.body_id,
-                        ObligationCauseCode::BindingObligation(proj.def_id, pred_span),
+                        ObligationCauseCode::WhereClause(proj.def_id, pred_span),
                     ),
                     self.param_env,
                     pred,
@@ -1494,14 +1491,16 @@
     let mut error_found = None;
     let impl_m_generics = tcx.generics_of(impl_m.def_id);
     let trait_m_generics = tcx.generics_of(trait_m.def_id);
-    let impl_m_type_params = impl_m_generics.params.iter().filter_map(|param| match param.kind {
-        GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
-        GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,
-    });
-    let trait_m_type_params = trait_m_generics.params.iter().filter_map(|param| match param.kind {
-        GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
-        GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,
-    });
+    let impl_m_type_params =
+        impl_m_generics.own_params.iter().filter_map(|param| match param.kind {
+            GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
+            GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,
+        });
+    let trait_m_type_params =
+        trait_m_generics.own_params.iter().filter_map(|param| match param.kind {
+            GenericParamDefKind::Type { synthetic, .. } => Some((param.def_id, synthetic)),
+            GenericParamDefKind::Lifetime | GenericParamDefKind::Const { .. } => None,
+        });
     for ((impl_def_id, impl_synthetic), (trait_def_id, trait_synthetic)) in
         iter::zip(impl_m_type_params, trait_m_type_params)
     {
@@ -1639,7 +1638,7 @@
     assert_eq!(impl_item.kind, trait_item.kind);
 
     let ty_const_params_of = |def_id| {
-        tcx.generics_of(def_id).params.iter().filter(|param| {
+        tcx.generics_of(def_id).own_params.iter().filter(|param| {
             matches!(
                 param.kind,
                 GenericParamDefKind::Const { .. } | GenericParamDefKind::Type { .. }
@@ -1754,7 +1753,7 @@
     let impl_ty = tcx.type_of(impl_ct_def_id).instantiate_identity();
 
     let trait_ty = tcx.type_of(trait_ct.def_id).instantiate(tcx, trait_to_impl_args);
-    let code = ObligationCauseCode::CompareImplItemObligation {
+    let code = ObligationCauseCode::CompareImplItem {
         impl_item_def_id: impl_ct_def_id,
         trait_item_def_id: trait_ct.def_id,
         kind: impl_ct.kind,
@@ -1926,7 +1925,7 @@
         let cause = ObligationCause::new(
             span,
             impl_ty_def_id,
-            ObligationCauseCode::CompareImplItemObligation {
+            ObligationCauseCode::CompareImplItem {
                 impl_item_def_id: impl_ty.def_id.expect_local(),
                 trait_item_def_id: trait_ty.def_id,
                 kind: impl_ty.kind,
@@ -2013,11 +2012,7 @@
         },
     );
     let mk_cause = |span: Span| {
-        let code = if span.is_dummy() {
-            traits::ItemObligation(trait_ty.def_id)
-        } else {
-            traits::BindingObligation(trait_ty.def_id, span)
-        };
+        let code = ObligationCauseCode::WhereClause(trait_ty.def_id, span);
         ObligationCause::new(impl_ty_span, impl_ty_def_id, code)
     };
 
@@ -2140,7 +2135,7 @@
         };
 
         let mut bound_vars: smallvec::SmallVec<[ty::BoundVariableKind; 8]> =
-            smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).params.len());
+            smallvec::SmallVec::with_capacity(tcx.generics_of(impl_ty.def_id).own_params.len());
         // Extend the impl's identity args with late-bound GAT vars
         let normalize_impl_ty_args = ty::GenericArgs::identity_for_item(tcx, container_id)
             .extend_to(tcx, impl_ty.def_id, |param, _| match param.kind {
@@ -2211,12 +2206,12 @@
             _ => predicates.push(
                 ty::Binder::bind_with_vars(
                     ty::ProjectionPredicate {
-                        projection_ty: ty::AliasTy::new(tcx, trait_ty.def_id, rebased_args),
+                        projection_term: ty::AliasTerm::new(tcx, trait_ty.def_id, rebased_args),
                         term: normalize_impl_ty.into(),
                     },
                     bound_vars,
                 )
-                .to_predicate(tcx),
+                .upcast(tcx),
             ),
         };
     }
@@ -2253,9 +2248,9 @@
     };
 
     for error in errors {
-        if let traits::BindingObligation(def_id, _) = *error.root_obligation.cause.code()
+        if let ObligationCauseCode::WhereClause(def_id, _) = *error.root_obligation.cause.code()
             && def_id == async_future_def_id
-            && let Some(proj) = error.root_obligation.predicate.to_opt_poly_projection_pred()
+            && let Some(proj) = error.root_obligation.predicate.as_projection_clause()
             && let Some(proj) = proj.no_bound_vars()
             && infcx.can_eq(
                 error.root_obligation.param_env,
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
index a2a2008..ca08eee 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs
@@ -3,6 +3,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::{outlives::env::OutlivesEnvironment, TyCtxtInferExt};
 use rustc_lint_defs::builtin::{REFINING_IMPL_TRAIT_INTERNAL, REFINING_IMPL_TRAIT_REACHABLE};
+use rustc_middle::span_bug;
 use rustc_middle::traits::{ObligationCause, Reveal};
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperVisitable, TypeVisitable, TypeVisitor,
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index 82a6b6b..be412dd 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -5,6 +5,7 @@
 use rustc_errors::{codes::*, struct_span_code_err, ErrorGuaranteed};
 use rustc_infer::infer::outlives::env::OutlivesEnvironment;
 use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
+use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::ty::util::CheckRegions;
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, TyCtxt};
@@ -139,7 +140,7 @@
     for (pred, span) in tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) {
         let normalize_cause = traits::ObligationCause::misc(span, adt_def_id);
         let pred = ocx.normalize(&normalize_cause, param_env, pred);
-        let cause = traits::ObligationCause::new(span, adt_def_id, traits::DropImpl);
+        let cause = traits::ObligationCause::new(span, adt_def_id, ObligationCauseCode::DropImpl);
         ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, pred));
     }
 
diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs
index d5908cf..25ac31c 100644
--- a/compiler/rustc_hir_analysis/src/check/entry.rs
+++ b/compiler/rustc_hir_analysis/src/check/entry.rs
@@ -1,6 +1,7 @@
 use rustc_hir as hir;
 use rustc_hir::Node;
 use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::span_bug;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::config::EntryFnType;
 use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
@@ -155,7 +156,7 @@
         [],
         expected_return_type,
         false,
-        hir::Unsafety::Normal,
+        hir::Safety::Safe,
         Abi::Rust,
     ));
 
@@ -251,7 +252,7 @@
                 [tcx.types.isize, Ty::new_imm_ptr(tcx, Ty::new_imm_ptr(tcx, tcx.types.u8))],
                 tcx.types.isize,
                 false,
-                hir::Unsafety::Normal,
+                hir::Safety::Safe,
                 Abi::Rust,
             ));
 
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index eb1fa1b..50fe203 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -9,6 +9,7 @@
 
 use rustc_errors::{codes::*, struct_span_code_err, DiagMessage};
 use rustc_hir as hir;
+use rustc_middle::bug;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefId;
@@ -70,13 +71,13 @@
 }
 
 /// Returns the unsafety of the given intrinsic.
-pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hir::Unsafety {
+pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) -> hir::Safety {
     let has_safe_attr = if tcx.has_attr(intrinsic_id, sym::rustc_intrinsic) {
-        tcx.fn_sig(intrinsic_id).skip_binder().unsafety()
+        tcx.fn_sig(intrinsic_id).skip_binder().safety()
     } else {
         match tcx.has_attr(intrinsic_id, sym::rustc_safe_intrinsic) {
-            true => hir::Unsafety::Normal,
-            false => hir::Unsafety::Unsafe,
+            true => hir::Safety::Safe,
+            false => hir::Safety::Unsafe,
         }
     };
     let is_in_list = match tcx.item_name(intrinsic_id.into()) {
@@ -135,8 +136,8 @@
         | sym::fmul_algebraic
         | sym::fdiv_algebraic
         | sym::frem_algebraic
-        | sym::const_eval_select => hir::Unsafety::Normal,
-        _ => hir::Unsafety::Unsafe,
+        | sym::const_eval_select => hir::Safety::Safe,
+        _ => hir::Safety::Unsafe,
     };
 
     if has_safe_attr != is_in_list {
@@ -196,7 +197,7 @@
         })
     };
 
-    let (n_tps, n_lts, n_cts, inputs, output, unsafety) = if name_str.starts_with("atomic_") {
+    let (n_tps, n_lts, n_cts, inputs, output, safety) = if name_str.starts_with("atomic_") {
         let split: Vec<&str> = name_str.split('_').collect();
         assert!(split.len() >= 2, "Atomic intrinsic in an incorrect format");
 
@@ -218,9 +219,9 @@
                 return;
             }
         };
-        (n_tps, 0, 0, inputs, output, hir::Unsafety::Unsafe)
+        (n_tps, 0, 0, inputs, output, hir::Safety::Unsafe)
     } else {
-        let unsafety = intrinsic_operation_unsafety(tcx, intrinsic_id);
+        let safety = intrinsic_operation_unsafety(tcx, intrinsic_id);
         let (n_tps, n_cts, inputs, output) = match intrinsic_name {
             sym::abort => (0, 0, vec![], tcx.types.never),
             sym::unreachable => (0, 0, vec![], tcx.types.never),
@@ -513,14 +514,14 @@
                     [mut_u8],
                     tcx.types.unit,
                     false,
-                    hir::Unsafety::Normal,
+                    hir::Safety::Safe,
                     Abi::Rust,
                 ));
                 let catch_fn_ty = ty::Binder::dummy(tcx.mk_fn_sig(
                     [mut_u8, mut_u8],
                     tcx.types.unit,
                     false,
-                    hir::Unsafety::Normal,
+                    hir::Safety::Safe,
                     Abi::Rust,
                 ));
                 (
@@ -606,6 +607,7 @@
             | sym::simd_bitreverse
             | sym::simd_ctlz
             | sym::simd_cttz
+            | sym::simd_ctpop
             | sym::simd_fsqrt
             | sym::simd_fsin
             | sym::simd_fcos
@@ -655,9 +657,9 @@
                 return;
             }
         };
-        (n_tps, 0, n_cts, inputs, output, unsafety)
+        (n_tps, 0, n_cts, inputs, output, safety)
     };
-    let sig = tcx.mk_fn_sig(inputs, output, false, unsafety, abi);
+    let sig = tcx.mk_fn_sig(inputs, output, false, safety, abi);
     let sig = ty::Binder::bind_with_vars(sig, bound_vars);
     equate_intrinsic_type(tcx, span, intrinsic_id, n_tps, n_lts, n_cts, sig)
 }
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 45ccd0f..b09de1a 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -1,6 +1,7 @@
 use rustc_ast::InlineAsmTemplatePiece;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir as hir;
+use rustc_middle::bug;
 use rustc_middle::ty::{self, Article, FloatTy, IntTy, Ty, TyCtxt, TypeVisitableExt, UintTy};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index eb0ffc1..0083da2 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -90,6 +90,7 @@
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArgs, GenericArgsRef};
+use rustc_middle::{bug, span_bug};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{def_id::CRATE_DEF_ID, BytePos, Span, Symbol, DUMMY_SP};
@@ -343,9 +344,10 @@
                 let mut projections_str = vec![];
                 for projection in &projections {
                     let p = projection.skip_binder();
-                    let alias_ty = p.projection_ty;
-                    if bound == tcx.parent(alias_ty.def_id) && alias_ty.self_ty() == ty {
-                        let name = tcx.item_name(alias_ty.def_id);
+                    if bound == tcx.parent(p.projection_term.def_id)
+                        && p.projection_term.self_ty() == ty
+                    {
+                        let name = tcx.item_name(p.projection_term.def_id);
                         projections_str.push(format!("{} = {}", name, p.term));
                     }
                 }
@@ -454,7 +456,7 @@
 
     let output = if !output.is_unit() { format!(" -> {output}") } else { String::new() };
 
-    let unsafety = sig.unsafety.prefix_str();
+    let safety = sig.safety.prefix_str();
     let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates);
 
     // FIXME: this is not entirely correct, as the lifetimes from borrowed params will
@@ -462,9 +464,7 @@
     // lifetimes between the `impl` and the `trait`, but this should be good enough to
     // fill in a significant portion of the missing code, and other subsequent
     // suggestions can help the user fix the code.
-    format!(
-        "{unsafety}{asyncness}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}"
-    )
+    format!("{safety}{asyncness}fn {ident}{generics}({args}){output}{where_clauses} {{ todo!() }}")
 }
 
 /// Return placeholder code for the given associated item.
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index d2ea51f..4540310 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -13,6 +13,7 @@
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Arm, Block, Expr, LetStmt, Pat, PatKind, Stmt};
 use rustc_index::Idx;
+use rustc_middle::bug;
 use rustc_middle::middle::region::*;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::source_map;
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 5b127e0..e8ede80 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -20,10 +20,11 @@
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::trait_def::TraitSpecializationKind;
 use rustc_middle::ty::{
-    self, AdtKind, GenericParamDefKind, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor,
+    self, AdtKind, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
+    TypeVisitable, TypeVisitableExt, TypeVisitor, Upcast,
 };
 use rustc_middle::ty::{GenericArgKind, GenericArgs};
+use rustc_middle::{bug, span_bug};
 use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::{Span, DUMMY_SP};
@@ -431,7 +432,7 @@
             }
             let gat_generics = tcx.generics_of(gat_def_id);
             // FIXME(jackh726): we can also warn in the more general case
-            if gat_generics.params.is_empty() {
+            if gat_generics.is_own_empty() {
                 continue;
             }
 
@@ -684,7 +685,7 @@
                 // `Self: 'me`.)
                 bounds.insert(
                     ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty_param, region_param))
-                        .to_predicate(tcx),
+                        .upcast(tcx),
                 );
             }
         }
@@ -729,7 +730,7 @@
                         region_a_param,
                         region_b_param,
                     ))
-                    .to_predicate(tcx),
+                    .upcast(tcx),
                 );
             }
         }
@@ -1136,7 +1137,7 @@
                     traits::ObligationCause::new(
                         hir_ty.span,
                         wfcx.body_def_id,
-                        traits::FieldSized {
+                        ObligationCauseCode::FieldSized {
                             adt_kind: match &item.kind {
                                 ItemKind::Struct(..) => AdtKind::Struct,
                                 ItemKind::Union(..) => AdtKind::Union,
@@ -1161,7 +1162,7 @@
                 let cause = traits::ObligationCause::new(
                     tcx.def_span(discr_def_id),
                     wfcx.body_def_id,
-                    traits::MiscObligation,
+                    ObligationCauseCode::Misc,
                 );
                 wfcx.register_obligation(traits::Obligation::new(
                     tcx,
@@ -1278,7 +1279,11 @@
         wfcx.register_wf_obligation(ty_span, Some(WellFormedLoc::Ty(item_id)), item_ty.into());
         if forbid_unsized {
             wfcx.register_bound(
-                traits::ObligationCause::new(ty_span, wfcx.body_def_id, traits::WellFormed(None)),
+                traits::ObligationCause::new(
+                    ty_span,
+                    wfcx.body_def_id,
+                    ObligationCauseCode::WellFormed(None),
+                ),
                 wfcx.param_env,
                 item_ty,
                 tcx.require_lang_item(LangItem::Sized, None),
@@ -1293,7 +1298,11 @@
 
         if should_check_for_sync {
             wfcx.register_bound(
-                traits::ObligationCause::new(ty_span, wfcx.body_def_id, traits::SharedStatic),
+                traits::ObligationCause::new(
+                    ty_span,
+                    wfcx.body_def_id,
+                    ObligationCauseCode::SharedStatic,
+                ),
                 wfcx.param_env,
                 item_ty,
                 tcx.require_lang_item(LangItem::Sync, Some(ty_span)),
@@ -1341,12 +1350,12 @@
                         // We already have a better span.
                         continue;
                     }
-                    if let Some(pred) = obligation.predicate.to_opt_poly_trait_pred()
+                    if let Some(pred) = obligation.predicate.as_trait_clause()
                         && pred.skip_binder().self_ty() == trait_ref.self_ty()
                     {
                         obligation.cause.span = hir_self_ty.span;
                     }
-                    if let Some(pred) = obligation.predicate.to_opt_poly_projection_pred()
+                    if let Some(pred) = obligation.predicate.as_projection_clause()
                         && pred.skip_binder().self_ty() == trait_ref.self_ty()
                     {
                         obligation.cause.span = hir_self_ty.span;
@@ -1400,7 +1409,7 @@
     //     struct Foo<T = Vec<[u32]>> { .. }
     //
     // Here, the default `Vec<[u32]>` is not WF because `[u32]: Sized` does not hold.
-    for param in &generics.params {
+    for param in &generics.own_params {
         match param.kind {
             GenericParamDefKind::Type { .. } => {
                 if is_our_default(param) {
@@ -1542,7 +1551,7 @@
             let cause = traits::ObligationCause::new(
                 sp,
                 wfcx.body_def_id,
-                traits::ItemObligation(def_id.to_def_id()),
+                ObligationCauseCode::WhereClause(def_id.to_def_id(), DUMMY_SP),
             );
             traits::Obligation::new(tcx, cause, wfcx.param_env, pred)
         });
@@ -1879,7 +1888,7 @@
             continue;
         }
 
-        let ty_param = &ty_generics.params[index];
+        let ty_param = &ty_generics.own_params[index];
         let hir_param = &hir_generics.params[index];
 
         if ty_param.def_id != hir_param.def_id.into() {
@@ -1982,7 +1991,11 @@
 
                 let obligation = traits::Obligation::new(
                     tcx,
-                    traits::ObligationCause::new(span, self.body_def_id, traits::TrivialBound),
+                    traits::ObligationCause::new(
+                        span,
+                        self.body_def_id,
+                        ObligationCauseCode::TrivialBound,
+                    ),
                     empty_env,
                     pred,
                 );
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 0b6c60e..8f0aba1 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -14,6 +14,7 @@
 use rustc_infer::infer::{self, RegionResolutionError};
 use rustc_infer::traits::Obligation;
 use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
+use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 4a85e99..e2d3ff5 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -10,6 +10,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_middle::bug;
 use rustc_middle::ty::fast_reject::{simplify_type, SimplifiedType, TreatParams};
 use rustc_middle::ty::{self, CrateInherentImpls, Ty, TyCtxt};
 use rustc_span::symbol::sym;
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 819e092..bdac0d9 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -10,6 +10,7 @@
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
+use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_trait_selection::traits::{self, IsFirstInputType, UncoveredTyParams};
 use rustc_trait_selection::traits::{OrphanCheckErr, OrphanCheckMode};
@@ -571,7 +572,7 @@
         if let Some(def_id) = origin.param_def_id {
             // The generics of an `impl` don't have a parent, we can index directly.
             let index = self.generics.param_def_id_to_index[&def_id];
-            let name = self.generics.params[index as usize].name;
+            let name = self.generics.own_params[index as usize].name;
 
             Ty::new_param(self.infcx.tcx, index, name)
         } else {
diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
index 13ce4f0..5fe21e9 100644
--- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
@@ -2,7 +2,8 @@
 //! crate or pertains to a type defined in this crate.
 
 use rustc_errors::{codes::*, struct_span_code_err};
-use rustc_hir::Unsafety;
+use rustc_hir::Safety;
+use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{ImplPolarity::*, ImplTraitHeader, TraitDef, TyCtxt};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::ErrorGuaranteed;
@@ -14,11 +15,11 @@
     trait_def: &TraitDef,
 ) -> Result<(), ErrorGuaranteed> {
     let unsafe_attr =
-        tcx.generics_of(def_id).params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
+        tcx.generics_of(def_id).own_params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
     let trait_ref = trait_header.trait_ref.instantiate_identity();
 
-    match (trait_def.unsafety, unsafe_attr, trait_header.unsafety, trait_header.polarity) {
-        (Unsafety::Normal, None, Unsafety::Unsafe, Positive | Reservation) => {
+    match (trait_def.safety, unsafe_attr, trait_header.safety, trait_header.polarity) {
+        (Safety::Safe, None, Safety::Unsafe, Positive | Reservation) => {
             let span = tcx.def_span(def_id);
             return Err(struct_span_code_err!(
                 tcx.dcx(),
@@ -36,7 +37,7 @@
             .emit());
         }
 
-        (Unsafety::Unsafe, _, Unsafety::Normal, Positive | Reservation) => {
+        (Safety::Unsafe, _, Safety::Safe, Positive | Reservation) => {
             let span = tcx.def_span(def_id);
             return Err(struct_span_code_err!(
                 tcx.dcx(),
@@ -60,7 +61,7 @@
             .emit());
         }
 
-        (Unsafety::Normal, Some(attr_name), Unsafety::Normal, Positive | Reservation) => {
+        (Safety::Safe, Some(attr_name), Safety::Safe, Positive | Reservation) => {
             let span = tcx.def_span(def_id);
             return Err(struct_span_code_err!(
                 tcx.dcx(),
@@ -84,14 +85,14 @@
             .emit());
         }
 
-        (_, _, Unsafety::Unsafe, Negative) => {
+        (_, _, Safety::Unsafe, Negative) => {
             // Reported in AST validation
             assert!(tcx.dcx().has_errors().is_some(), "unsafe negative impl");
             Ok(())
         }
-        (_, _, Unsafety::Normal, Negative)
-        | (Unsafety::Unsafe, _, Unsafety::Unsafe, Positive | Reservation)
-        | (Unsafety::Normal, Some(_), Unsafety::Unsafe, Positive | Reservation)
-        | (Unsafety::Normal, None, Unsafety::Normal, _) => Ok(()),
+        (_, _, Safety::Safe, Negative)
+        | (Safety::Unsafe, _, Safety::Unsafe, Positive | Reservation)
+        | (Safety::Safe, Some(_), Safety::Unsafe, Positive | Reservation)
+        | (Safety::Safe, None, Safety::Safe, _) => Ok(()),
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 9198ceb..b760b86 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -14,6 +14,7 @@
 //! At present, however, we do run collection across all items in the
 //! crate as a kind of pass. This should eventually be factored away.
 
+use rustc_ast::Recovered;
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
 use rustc_data_structures::unord::UnordMap;
@@ -28,7 +29,8 @@
 use rustc_middle::hir::nested_filter;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::util::{Discr, IntTypeExt};
-use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, Ty, TyCtxt, Upcast};
+use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::FieldIdx;
@@ -1005,10 +1007,7 @@
             vis: tcx.visibility(f.def_id),
         })
         .collect();
-    let recovered = match def {
-        hir::VariantData::Struct { recovered, .. } => *recovered,
-        _ => false,
-    };
+    let recovered = matches!(def, hir::VariantData::Struct { recovered: Recovered::Yes(_), .. });
     ty::VariantDef::new(
         ident.name,
         variant_did.map(LocalDefId::to_def_id),
@@ -1103,11 +1102,11 @@
 fn trait_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::TraitDef {
     let item = tcx.hir().expect_item(def_id);
 
-    let (is_auto, unsafety, items) = match item.kind {
-        hir::ItemKind::Trait(is_auto, unsafety, .., items) => {
-            (is_auto == hir::IsAuto::Yes, unsafety, items)
+    let (is_auto, safety, items) = match item.kind {
+        hir::ItemKind::Trait(is_auto, safety, .., items) => {
+            (is_auto == hir::IsAuto::Yes, safety, items)
         }
-        hir::ItemKind::TraitAlias(..) => (false, hir::Unsafety::Normal, &[][..]),
+        hir::ItemKind::TraitAlias(..) => (false, hir::Safety::Safe, &[][..]),
         _ => span_bug!(item.span, "trait_def_of_item invoked on non-trait"),
     };
 
@@ -1118,8 +1117,24 @@
 
     let is_marker = tcx.has_attr(def_id, sym::marker);
     let rustc_coinductive = tcx.has_attr(def_id, sym::rustc_coinductive);
-    let skip_array_during_method_dispatch =
-        tcx.has_attr(def_id, sym::rustc_skip_array_during_method_dispatch);
+
+    // FIXME: We could probably do way better attribute validation here.
+    let mut skip_array_during_method_dispatch = false;
+    let mut skip_boxed_slice_during_method_dispatch = false;
+    for attr in tcx.get_attrs(def_id, sym::rustc_skip_during_method_dispatch) {
+        if let Some(lst) = attr.meta_item_list() {
+            for item in lst {
+                if let Some(ident) = item.ident() {
+                    match ident.as_str() {
+                        "array" => skip_array_during_method_dispatch = true,
+                        "boxed_slice" => skip_boxed_slice_during_method_dispatch = true,
+                        _ => (),
+                    }
+                }
+            }
+        }
+    }
+
     let specialization_kind = if tcx.has_attr(def_id, sym::rustc_unsafe_specialization_marker) {
         ty::trait_def::TraitSpecializationKind::Marker
     } else if tcx.has_attr(def_id, sym::rustc_specialization_trait) {
@@ -1248,12 +1263,13 @@
 
     ty::TraitDef {
         def_id: def_id.to_def_id(),
-        unsafety,
+        safety,
         paren_sugar,
         has_auto_impl: is_auto,
         is_marker,
         is_coinductive: rustc_coinductive || is_auto,
         skip_array_during_method_dispatch,
+        skip_boxed_slice_during_method_dispatch,
         specialization_kind,
         must_implement_one_of,
         implement_via_object,
@@ -1287,7 +1303,7 @@
             {
                 icx.lowerer().lower_fn_ty(
                     hir_id,
-                    sig.header.unsafety,
+                    sig.header.safety,
                     sig.header.abi,
                     sig.decl,
                     Some(generics),
@@ -1302,14 +1318,9 @@
             kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
             generics,
             ..
-        }) => icx.lowerer().lower_fn_ty(
-            hir_id,
-            header.unsafety,
-            header.abi,
-            decl,
-            Some(generics),
-            None,
-        ),
+        }) => {
+            icx.lowerer().lower_fn_ty(hir_id, header.safety, header.abi, decl, Some(generics), None)
+        }
 
         ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
             let abi = tcx.hir().get_foreign_abi(hir_id);
@@ -1322,8 +1333,8 @@
             let inputs = data.fields().iter().map(|f| tcx.type_of(f.def_id).instantiate_identity());
             // constructors for structs with `layout_scalar_valid_range` are unsafe to call
             let safety = match tcx.layout_scalar_valid_range(adt_def_id) {
-                (Bound::Unbounded, Bound::Unbounded) => hir::Unsafety::Normal,
-                _ => hir::Unsafety::Unsafe,
+                (Bound::Unbounded, Bound::Unbounded) => hir::Safety::Safe,
+                _ => hir::Safety::Unsafe,
             };
             ty::Binder::dummy(tcx.mk_fn_sig(inputs, ty, false, safety, abi::Abi::Rust))
         }
@@ -1410,13 +1421,13 @@
                 fn_sig.inputs().iter().copied(),
                 recovered_ret_ty.unwrap_or_else(|| Ty::new_error(tcx, guar)),
                 fn_sig.c_variadic,
-                fn_sig.unsafety,
+                fn_sig.safety,
                 fn_sig.abi,
             ))
         }
         None => icx.lowerer().lower_fn_ty(
             hir_id,
-            sig.header.unsafety,
+            sig.header.safety,
             sig.header.abi,
             sig.decl,
             Some(generics),
@@ -1575,7 +1586,7 @@
             };
             ty::ImplTraitHeader {
                 trait_ref: ty::EarlyBinder::bind(trait_ref),
-                unsafety: impl_.unsafety,
+                safety: impl_.safety,
                 polarity: polarity_of_impl(tcx, def_id, impl_, item.span)
             }
         })
@@ -1666,7 +1677,7 @@
             def_id, inferred_outlives,
         );
         let inferred_outlives_iter =
-            inferred_outlives.iter().map(|(clause, span)| ((*clause).to_predicate(tcx), *span));
+            inferred_outlives.iter().map(|(clause, span)| ((*clause).upcast(tcx), *span));
         if result.predicates.is_empty() {
             result.predicates = tcx.arena.alloc_from_iter(inferred_outlives_iter);
         } else {
@@ -1686,14 +1697,14 @@
     decl: &'tcx hir::FnDecl<'tcx>,
     abi: abi::Abi,
 ) -> ty::PolyFnSig<'tcx> {
-    let unsafety = if abi == abi::Abi::RustIntrinsic {
+    let safety = if abi == abi::Abi::RustIntrinsic {
         intrinsic_operation_unsafety(tcx, def_id)
     } else {
-        hir::Unsafety::Unsafe
+        hir::Safety::Unsafe
     };
     let hir_id = tcx.local_def_id_to_hir_id(def_id);
     let fty =
-        ItemCtxt::new(tcx, def_id).lowerer().lower_fn_ty(hir_id, unsafety, abi, decl, None, None);
+        ItemCtxt::new(tcx, def_id).lowerer().lower_fn_ty(hir_id, safety, abi, decl, None, None);
 
     // Feature gate SIMD types in FFI, since I am not sure that the
     // ABIs are handled at all correctly. -huonw
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index f83ddc5..6b41f79 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -22,28 +22,28 @@
         let trait_def_id = tcx.parent(fn_def_id);
         let opaque_ty_generics = tcx.generics_of(opaque_def_id);
         let opaque_ty_parent_count = opaque_ty_generics.parent_count;
-        let mut params = opaque_ty_generics.params.clone();
+        let mut own_params = opaque_ty_generics.own_params.clone();
 
         let parent_generics = tcx.generics_of(trait_def_id);
-        let parent_count = parent_generics.parent_count + parent_generics.params.len();
+        let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
 
-        let mut trait_fn_params = tcx.generics_of(fn_def_id).params.clone();
+        let mut trait_fn_params = tcx.generics_of(fn_def_id).own_params.clone();
 
-        for param in &mut params {
+        for param in &mut own_params {
             param.index = param.index + parent_count as u32 + trait_fn_params.len() as u32
                 - opaque_ty_parent_count as u32;
         }
 
-        trait_fn_params.extend(params);
-        params = trait_fn_params;
+        trait_fn_params.extend(own_params);
+        own_params = trait_fn_params;
 
         let param_def_id_to_index =
-            params.iter().map(|param| (param.def_id, param.index)).collect();
+            own_params.iter().map(|param| (param.def_id, param.index)).collect();
 
         return ty::Generics {
             parent: Some(trait_def_id),
             parent_count,
-            params,
+            own_params,
             param_def_id_to_index,
             has_self: opaque_ty_generics.has_self,
             has_late_bound_regions: opaque_ty_generics.has_late_bound_regions,
@@ -124,9 +124,9 @@
                     let generics = tcx.generics_of(parent_def_id.to_def_id());
                     let param_def_idx = generics.param_def_id_to_index[&param_id.to_def_id()];
                     // In the above example this would be .params[..N#0]
-                    let params = generics.params_to(param_def_idx as usize, tcx).to_owned();
+                    let own_params = generics.params_to(param_def_idx as usize, tcx).to_owned();
                     let param_def_id_to_index =
-                        params.iter().map(|param| (param.def_id, param.index)).collect();
+                        own_params.iter().map(|param| (param.def_id, param.index)).collect();
 
                     return ty::Generics {
                         // we set the parent of these generics to be our parent's parent so that we
@@ -134,7 +134,7 @@
                         // struct Foo<const N: usize, const M: usize = { ... }>;
                         parent: generics.parent,
                         parent_count: generics.parent_count,
-                        params,
+                        own_params,
                         param_def_id_to_index,
                         has_self: generics.has_self,
                         has_late_bound_regions: generics.has_late_bound_regions,
@@ -274,17 +274,17 @@
         parent_has_self = generics.has_self;
         host_effect_index = generics.host_effect_index;
         own_start = generics.count() as u32;
-        generics.parent_count + generics.params.len()
+        generics.parent_count + generics.own_params.len()
     });
 
-    let mut params: Vec<_> = Vec::with_capacity(hir_generics.params.len() + has_self as usize);
+    let mut own_params: Vec<_> = Vec::with_capacity(hir_generics.params.len() + has_self as usize);
 
     if let Some(opt_self) = opt_self {
-        params.push(opt_self);
+        own_params.push(opt_self);
     }
 
     let early_lifetimes = super::early_bound_lifetimes_from_generics(tcx, hir_generics);
-    params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
+    own_params.extend(early_lifetimes.enumerate().map(|(i, param)| ty::GenericParamDef {
         name: param.name.ident().name,
         index: own_start + i as u32,
         def_id: param.def_id.to_def_id(),
@@ -293,7 +293,7 @@
     }));
 
     // Now create the real type and const parameters.
-    let type_start = own_start - has_self as u32 + params.len() as u32;
+    let type_start = own_start - has_self as u32 + own_params.len() as u32;
     let mut i: u32 = 0;
     let mut next_index = || {
         let prev = i;
@@ -304,7 +304,7 @@
     const TYPE_DEFAULT_NOT_ALLOWED: &'static str = "defaults for type parameters are only allowed in \
     `struct`, `enum`, `type`, or `trait` definitions";
 
-    params.extend(hir_generics.params.iter().filter_map(|param| match param.kind {
+    own_params.extend(hir_generics.params.iter().filter_map(|param| match param.kind {
         GenericParamKind::Lifetime { .. } => None,
         GenericParamKind::Type { default, synthetic, .. } => {
             if default.is_some() {
@@ -404,7 +404,7 @@
             ][..],
         };
 
-        params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef {
+        own_params.extend(dummy_args.iter().map(|&arg| ty::GenericParamDef {
             index: next_index(),
             name: Symbol::intern(arg),
             def_id: def_id.to_def_id(),
@@ -415,7 +415,7 @@
 
     // provide junk type parameter defs for const blocks.
     if let Node::ConstBlock(_) = node {
-        params.push(ty::GenericParamDef {
+        own_params.push(ty::GenericParamDef {
             index: next_index(),
             name: Symbol::intern("<const_ty>"),
             def_id: def_id.to_def_id(),
@@ -424,12 +424,13 @@
         });
     }
 
-    let param_def_id_to_index = params.iter().map(|param| (param.def_id, param.index)).collect();
+    let param_def_id_to_index =
+        own_params.iter().map(|param| (param.def_id, param.index)).collect();
 
     ty::Generics {
         parent: parent_def_id,
         parent_count,
-        params,
+        own_params,
         param_def_id_to_index,
         has_self: has_self || parent_has_self,
         has_late_bound_regions: has_late_bound_regions(tcx, node),
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 02291cc..dd1d209 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -5,6 +5,7 @@
 use rustc_infer::traits::util;
 use rustc_middle::ty::GenericArgs;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::{DefId, LocalDefId};
 use rustc_span::Span;
 
@@ -39,7 +40,7 @@
     let bounds_from_parent = trait_predicates.predicates.iter().copied().filter(|(pred, _)| {
         match pred.kind().skip_binder() {
             ty::ClauseKind::Trait(tr) => tr.self_ty() == item_ty,
-            ty::ClauseKind::Projection(proj) => proj.projection_ty.self_ty() == item_ty,
+            ty::ClauseKind::Projection(proj) => proj.projection_term.self_ty() == item_ty,
             ty::ClauseKind::TypeOutlives(outlives) => outlives.0 == item_ty,
             _ => false,
         }
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 4726572..db36aba 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -9,7 +9,8 @@
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, ToPredicate};
+use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, Upcast};
+use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
@@ -39,11 +40,13 @@
         // `tcx.def_span(def_id);`
         let span = DUMMY_SP;
 
-        result.predicates =
-            tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
-                ty::TraitRef::identity(tcx, def_id).to_predicate(tcx),
-                span,
-            ))));
+        result.predicates = tcx.arena.alloc_from_iter(
+            result
+                .predicates
+                .iter()
+                .copied()
+                .chain(std::iter::once((ty::TraitRef::identity(tcx, def_id).upcast(tcx), span))),
+        );
     }
     debug!("predicates_of(def_id={:?}) = {:?}", def_id, result);
     result
@@ -73,8 +76,8 @@
             // opaque lifetimes, which explains the slicing below.
             compute_bidirectional_outlives_predicates(
                 tcx,
-                &tcx.generics_of(def_id.to_def_id()).params
-                    [tcx.generics_of(fn_def_id).params.len()..],
+                &tcx.generics_of(def_id.to_def_id()).own_params
+                    [tcx.generics_of(fn_def_id).own_params.len()..],
                 &mut predicates,
             );
 
@@ -164,7 +167,7 @@
     // (see below). Recall that a default impl is not itself an impl, but rather a
     // set of defaults that can be incorporated into another impl.
     if let Some(trait_ref) = is_default_impl_trait {
-        predicates.insert((trait_ref.to_predicate(tcx), tcx.def_span(def_id)));
+        predicates.insert((trait_ref.upcast(tcx), tcx.def_span(def_id)));
     }
 
     // Collect the predicates that were written inline by the user on each
@@ -195,10 +198,8 @@
                     .no_bound_vars()
                     .expect("const parameters cannot be generic");
                 let ct = icx.lowerer().lower_const_param(param.hir_id, ct_ty);
-                predicates.insert((
-                    ty::ClauseKind::ConstArgHasType(ct, ct_ty).to_predicate(tcx),
-                    param.span,
-                ));
+                predicates
+                    .insert((ty::ClauseKind::ConstArgHasType(ct, ct_ty).upcast(tcx), param.span));
             }
         }
     }
@@ -227,7 +228,7 @@
                             ty::ClauseKind::WellFormed(ty.into()),
                             bound_vars,
                         );
-                        predicates.insert((predicate.to_predicate(tcx), span));
+                        predicates.insert((predicate.upcast(tcx), span));
                     }
                 }
 
@@ -256,8 +257,8 @@
                             )
                         }
                     };
-                    let pred = ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2))
-                        .to_predicate(tcx);
+                    let pred =
+                        ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(r1, r2)).upcast(tcx);
                     (pred, span)
                 }))
             }
@@ -300,7 +301,7 @@
         };
         debug!(?lifetimes);
 
-        compute_bidirectional_outlives_predicates(tcx, &generics.params, &mut predicates);
+        compute_bidirectional_outlives_predicates(tcx, &generics.own_params, &mut predicates);
         debug!(?predicates);
     }
 
@@ -327,12 +328,12 @@
             let span = tcx.def_span(param.def_id);
             predicates.push((
                 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(orig_lifetime, dup_lifetime))
-                    .to_predicate(tcx),
+                    .upcast(tcx),
                 span,
             ));
             predicates.push((
                 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(dup_lifetime, orig_lifetime))
-                    .to_predicate(tcx),
+                    .upcast(tcx),
                 span,
             ));
         }
@@ -353,8 +354,7 @@
             let ct = ty::Const::from_anon_const(self.tcx, c.def_id);
             if let ty::ConstKind::Unevaluated(_) = ct.kind() {
                 let span = self.tcx.def_span(c.def_id);
-                self.preds
-                    .insert((ty::ClauseKind::ConstEvaluatable(ct).to_predicate(self.tcx), span));
+                self.preds.insert((ty::ClauseKind::ConstEvaluatable(ct).upcast(self.tcx), span));
             }
         }
 
@@ -445,7 +445,9 @@
             .copied()
             .filter(|(pred, _)| match pred.kind().skip_binder() {
                 ty::ClauseKind::Trait(tr) => !is_assoc_item_ty(tr.self_ty()),
-                ty::ClauseKind::Projection(proj) => !is_assoc_item_ty(proj.projection_ty.self_ty()),
+                ty::ClauseKind::Projection(proj) => {
+                    !is_assoc_item_ty(proj.projection_term.self_ty())
+                }
                 ty::ClauseKind::TypeOutlives(outlives) => !is_assoc_item_ty(outlives.0),
                 _ => true,
             })
@@ -691,7 +693,7 @@
         && param_id == item_hir_id
     {
         let identity_trait_ref = ty::TraitRef::identity(tcx, item_def_id.to_def_id());
-        extend = Some((identity_trait_ref.to_predicate(tcx), item.span));
+        extend = Some((identity_trait_ref.upcast(tcx), item.span));
     }
 
     let icx = ItemCtxt::new(tcx, item_def_id);
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index a5f038d..5c77330 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -15,11 +15,11 @@
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirId, HirIdMap, LifetimeName, Node};
 use rustc_macros::extension;
-use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars::*;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor};
+use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -1562,7 +1562,7 @@
                 ObjectLifetimeDefault::Ambiguous => None,
             };
             generics
-                .params
+                .own_params
                 .iter()
                 .filter_map(|param| {
                     match self.tcx.def_kind(param.def_id) {
@@ -1668,7 +1668,7 @@
                         binding.ident,
                         ty::AssocKind::Fn,
                     ) {
-                    bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).params.iter().map(
+                    bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).own_params.iter().map(
                         |param| match param.kind {
                             ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
                                 ty::BoundRegionKind::BrNamed(param.def_id, param.name),
@@ -2003,7 +2003,8 @@
                     // just consider args to be unconstrained.
                     let generics = self.tcx.generics_of(alias_def);
                     let mut walker = ConstrainedCollectorPostHirTyLowering {
-                        arg_is_constrained: vec![false; generics.params.len()].into_boxed_slice(),
+                        arg_is_constrained: vec![false; generics.own_params.len()]
+                            .into_boxed_slice(),
                     };
                     walker.visit_ty(self.tcx.type_of(alias_def).instantiate_identity());
 
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 5ccfd06..1475e53 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -7,6 +7,7 @@
 use rustc_middle::ty::print::with_forced_trimmed_paths;
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Ident;
 use rustc_span::{Span, DUMMY_SP};
 
@@ -255,7 +256,7 @@
     debug!(?parent_node);
     debug!(?generics, ?arg_idx);
     if let Some(param_def_id) = generics
-        .params
+        .own_params
         .iter()
         .filter(|param| param.kind.is_ty_or_const())
         .nth(match generics.has_self && generics.parent.is_none() {
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
index b576591..1bec8c4 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -3,6 +3,7 @@
 use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{self as hir, def, Expr, ImplItem, Item, Node, TraitItem};
+use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index 3b8bb07..6201701 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -1,4 +1,5 @@
 use rustc_data_structures::fx::FxHashSet;
+use rustc_middle::bug;
 use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitor};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
@@ -197,7 +198,7 @@
                 // Special case: watch out for some kind of sneaky attempt
                 // to project out an associated type defined by this very
                 // trait.
-                let unbound_trait_ref = projection.projection_ty.trait_ref(tcx);
+                let unbound_trait_ref = projection.projection_term.trait_ref(tcx);
                 if Some(unbound_trait_ref) == impl_trait_ref {
                     continue;
                 }
@@ -207,7 +208,7 @@
                 //     `<<T as Bar>::Baz as Iterator>::Output = <U as Iterator>::Output`
                 // Then the projection only applies if `T` is known, but it still
                 // does not determine `U`.
-                let inputs = parameters_for(tcx, projection.projection_ty, true);
+                let inputs = parameters_for(tcx, projection.projection_term, true);
                 let relies_only_on_inputs = inputs.iter().all(|p| input_parameters.contains(p));
                 if !relies_only_on_inputs {
                     continue;
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
index 11bd3e52..b0ae73f 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/bounds.rs
@@ -5,6 +5,8 @@
 use rustc_hir as hir;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_middle::bug;
+use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TyCtxt};
 use rustc_span::symbol::Ident;
 use rustc_span::{ErrorGuaranteed, Span, Symbol};
@@ -325,7 +327,7 @@
             })
             .or_insert(binding.span);
 
-        let projection_ty = if let ty::AssocKind::Fn = assoc_kind {
+        let projection_term = if let ty::AssocKind::Fn = assoc_kind {
             let mut emitted_bad_param_err = None;
             // If we have an method return type bound, then we need to instantiate
             // the method's early bound params with suitable late-bound params.
@@ -379,7 +381,7 @@
             let output = if let ty::Alias(ty::Projection, alias_ty) = *output.skip_binder().kind()
                 && tcx.is_impl_trait_in_trait(alias_ty.def_id)
             {
-                alias_ty
+                alias_ty.into()
             } else {
                 return Err(tcx.dcx().emit_err(crate::errors::ReturnTypeNotationOnNonRpitit {
                     span: binding.span,
@@ -420,10 +422,7 @@
                 );
                 debug!(?alias_args);
 
-                // Note that we're indeed also using `AliasTy` (alias *type*) for associated
-                // *constants* to represent *const projections*. Alias *term* would be a more
-                // appropriate name but alas.
-                ty::AliasTy::new(tcx, assoc_item.def_id, alias_args)
+                ty::AliasTerm::new(tcx, assoc_item.def_id, alias_args)
             });
 
             // Provide the resolved type of the associated constant to `type_of(AnonConst)`.
@@ -460,7 +459,7 @@
                 //     for<'a> <T as Iterator>::Item = &'a str // <-- 'a is bad
                 //     for<'a> <T as FnMut<(&'a u32,)>>::Output = &'a str // <-- 'a is ok
                 let late_bound_in_projection_ty =
-                    tcx.collect_constrained_late_bound_regions(projection_ty);
+                    tcx.collect_constrained_late_bound_regions(projection_term);
                 let late_bound_in_term =
                     tcx.collect_referenced_late_bound_regions(trait_ref.rebind(term));
                 debug!(?late_bound_in_projection_ty);
@@ -489,8 +488,10 @@
 
                 bounds.push_projection_bound(
                     tcx,
-                    projection_ty
-                        .map_bound(|projection_ty| ty::ProjectionPredicate { projection_ty, term }),
+                    projection_term.map_bound(|projection_term| ty::ProjectionPredicate {
+                        projection_term,
+                        term,
+                    }),
                     binding.span,
                 );
             }
@@ -500,6 +501,8 @@
                 // NOTE: If `only_self_bounds` is true, do NOT expand this associated type bound into
                 // a trait predicate, since we only want to add predicates for the `Self` type.
                 if !only_self_bounds.0 {
+                    let projection_ty = projection_term
+                        .map_bound(|projection_term| projection_term.expect_ty(self.tcx()));
                     // Calling `skip_binder` is okay, because `lower_bounds` expects the `param_ty`
                     // parameter to have a skipped binder.
                     let param_ty = Ty::new_alias(tcx, ty::Projection, projection_ty.skip_binder());
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
index 8e64a94..168a370 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs
@@ -16,7 +16,9 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_infer::traits::FulfillmentError;
+use rustc_middle::bug;
 use rustc_middle::query::Key;
+use rustc_middle::ty::print::{PrintPolyTraitRefExt as _, PrintTraitRefExt as _};
 use rustc_middle::ty::GenericParamDefKind;
 use rustc_middle::ty::{self, suggest_constraining_type_param};
 use rustc_middle::ty::{AdtDef, Ty, TyCtxt, TypeVisitableExt};
@@ -624,25 +626,17 @@
             let bound_predicate = pred.kind();
             match bound_predicate.skip_binder() {
                 ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
-                    let pred = bound_predicate.rebind(pred);
                     // `<Foo as Iterator>::Item = String`.
-                    let projection_ty = pred.skip_binder().projection_ty;
+                    let projection_term = pred.projection_term;
+                    let quiet_projection_term =
+                        projection_term.with_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO));
 
-                    let args_with_infer_self = tcx.mk_args_from_iter(
-                        std::iter::once(Ty::new_var(tcx, ty::TyVid::ZERO).into())
-                            .chain(projection_ty.args.iter().skip(1)),
-                    );
+                    let term = pred.term;
+                    let obligation = format!("{projection_term} = {term}");
+                    let quiet = format!("{quiet_projection_term} = {term}");
 
-                    let quiet_projection_ty =
-                        ty::AliasTy::new(tcx, projection_ty.def_id, args_with_infer_self);
-
-                    let term = pred.skip_binder().term;
-
-                    let obligation = format!("{projection_ty} = {term}");
-                    let quiet = format!("{quiet_projection_ty} = {term}");
-
-                    bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
-                    Some((obligation, projection_ty.self_ty()))
+                    bound_span_label(projection_term.self_ty(), &obligation, &quiet);
+                    Some((obligation, projection_term.self_ty()))
                 }
                 ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => {
                     let p = poly_trait_ref.trait_ref;
@@ -1299,7 +1293,7 @@
         // same name as the assoc type name in type binding
         let generics = tcx.generics_of(def_id);
         let matching_param =
-            generics.params.iter().find(|p| p.name.as_str() == binding.ident.as_str());
+            generics.own_params.iter().find(|p| p.name.as_str() == binding.ident.as_str());
 
         // Now emit the appropriate suggestion
         if let Some(matching_param) = matching_param {
@@ -1415,7 +1409,7 @@
             // it was done based on the end of assoc segment but that sometimes
             // led to impossible spans and caused issues like #116473
             let args_span = args.span_ext.with_lo(args.span_ext.lo() - BytePos(2));
-            if tcx.generics_of(adt_def.did()).count() == 0 {
+            if tcx.generics_of(adt_def.did()).is_empty() {
                 // FIXME(estebank): we could also verify that the arguments being
                 // work for the `enum`, instead of just looking if it takes *any*.
                 err.span_suggestion_verbose(
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
index e6a7dfa..749f78e 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/generics.rs
@@ -196,7 +196,7 @@
     let mut args: SmallVec<[ty::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count);
     // Iterate over each segment of the path.
     while let Some((def_id, defs)) = stack.pop() {
-        let mut params = defs.params.iter().peekable();
+        let mut params = defs.own_params.iter().peekable();
 
         // If we have already computed the generic arguments for parents,
         // we can use those directly.
@@ -312,7 +312,7 @@
                                 // We're going to iterate over the parameters to sort them out, and
                                 // show that order to the user as a possible order for the parameters
                                 let mut param_types_present = defs
-                                    .params
+                                    .own_params
                                     .iter()
                                     .map(|param| (param.kind.to_ord(), param.clone()))
                                     .collect::<Vec<(ParamKindOrd, GenericParamDef)>>();
@@ -435,13 +435,13 @@
     // Subtracting from param count to ensure type params synthesized from `impl Trait`
     // cannot be explicitly specified.
     let synth_type_param_count = gen_params
-        .params
+        .own_params
         .iter()
         .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. }))
         .count();
     let named_type_param_count = param_counts.types - has_self as usize - synth_type_param_count;
     let synth_const_param_count = gen_params
-        .params
+        .own_params
         .iter()
         .filter(|param| {
             matches!(param.kind, ty::GenericParamDefKind::Const { is_host_effect: true, .. })
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
index f721344..0cd77fe 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs
@@ -40,10 +40,12 @@
 use rustc_infer::traits::ObligationCause;
 use rustc_middle::middle::stability::AllowUnstable;
 use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
+use rustc_middle::ty::print::PrintPolyTraitRefExt as _;
 use rustc_middle::ty::{
     self, Const, GenericArgKind, GenericArgsRef, GenericParamDefKind, ParamEnv, Ty, TyCtxt,
     TypeVisitableExt,
 };
+use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::AMBIGUOUS_ASSOCIATED_ITEMS;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::symbol::{kw, Ident, Symbol};
@@ -411,7 +413,7 @@
         // Traits always have `Self` as a generic parameter, which means they will not return early
         // here and so associated type bindings will be handled regardless of whether there are any
         // non-`Self` generic parameters.
-        if generics.params.is_empty() {
+        if generics.is_own_empty() {
             return (tcx.mk_args(parent_args), arg_count);
         }
 
@@ -2079,14 +2081,7 @@
 
                 Ty::new_fn_ptr(
                     tcx,
-                    self.lower_fn_ty(
-                        hir_ty.hir_id,
-                        bf.unsafety,
-                        bf.abi,
-                        bf.decl,
-                        None,
-                        Some(hir_ty),
-                    ),
+                    self.lower_fn_ty(hir_ty.hir_id, bf.safety, bf.abi, bf.decl, None, Some(hir_ty)),
                 )
             }
             hir::TyKind::TraitObject(bounds, lifetime, repr) => {
@@ -2308,11 +2303,11 @@
     }
 
     /// Lower a function type from the HIR to our internal notion of a function signature.
-    #[instrument(level = "debug", skip(self, hir_id, unsafety, abi, decl, generics, hir_ty), ret)]
+    #[instrument(level = "debug", skip(self, hir_id, safety, abi, decl, generics, hir_ty), ret)]
     pub fn lower_fn_ty(
         &self,
         hir_id: HirId,
-        unsafety: hir::Unsafety,
+        safety: hir::Safety,
         abi: abi::Abi,
         decl: &hir::FnDecl<'tcx>,
         generics: Option<&hir::Generics<'_>>,
@@ -2375,7 +2370,7 @@
 
         debug!(?output_ty);
 
-        let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, unsafety, abi);
+        let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, decl.c_variadic, safety, abi);
         let bare_fn_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars);
 
         if !self.allow_infer() && !(visitor.0.is_empty() && infer_replacements.is_empty()) {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
index 97ba946..4f7a39d 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/object_safety.rs
@@ -6,9 +6,10 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_lint_defs::builtin::UNUSED_ASSOCIATED_TYPE_BOUNDS;
+use rustc_middle::span_bug;
 use rustc_middle::ty::fold::BottomUpFolder;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
-use rustc_middle::ty::{DynKind, ToPredicate};
+use rustc_middle::ty::{self, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{DynKind, Upcast};
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_trait_selection::traits::error_reporting::report_object_safety_error;
 use rustc_trait_selection::traits::{self, hir_ty_lowering_object_safety_violations};
@@ -118,7 +119,7 @@
             .filter(|(trait_ref, _)| !tcx.trait_is_auto(trait_ref.def_id()));
 
         for (base_trait_ref, span) in regular_traits_refs_spans {
-            let base_pred: ty::Predicate<'tcx> = base_trait_ref.to_predicate(tcx);
+            let base_pred: ty::Predicate<'tcx> = base_trait_ref.upcast(tcx);
             for pred in traits::elaborate(tcx, [base_pred]).filter_only_self() {
                 debug!("observing object predicate `{pred:?}`");
 
@@ -227,7 +228,7 @@
                     .skip(1) // Remove `Self` for `ExistentialPredicate`.
                     .map(|(index, arg)| {
                         if arg == dummy_self.into() {
-                            let param = &generics.params[index];
+                            let param = &generics.own_params[index];
                             missing_type_params.push(param.name);
                             Ty::new_misc_error(tcx).into()
                         } else if arg.walk().any(|arg| arg == dummy_self.into()) {
@@ -280,11 +281,11 @@
 
         let existential_projections = projection_bounds.iter().map(|(bound, _)| {
             bound.map_bound(|mut b| {
-                assert_eq!(b.projection_ty.self_ty(), dummy_self);
+                assert_eq!(b.projection_term.self_ty(), dummy_self);
 
                 // Like for trait refs, verify that `dummy_self` did not leak inside default type
                 // parameters.
-                let references_self = b.projection_ty.args.iter().skip(1).any(|arg| {
+                let references_self = b.projection_term.args.iter().skip(1).any(|arg| {
                     if arg.walk().any(|arg| arg == dummy_self.into()) {
                         return true;
                     }
@@ -294,7 +295,7 @@
                     let guar = tcx
                         .dcx()
                         .span_delayed_bug(span, "trait object projection bounds reference `Self`");
-                    b.projection_ty = replace_dummy_self_with_error(tcx, b.projection_ty, guar);
+                    b.projection_term = replace_dummy_self_with_error(tcx, b.projection_term, guar);
                 }
 
                 ty::ExistentialProjection::erase_self_ty(tcx, b)
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index d6ba5fa..10101aa 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -4,6 +4,7 @@
 use rustc_hir::{ForeignItem, ForeignItemKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{ObligationCause, WellFormedLoc};
+use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::def_id::LocalDefId;
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index caa8509..002be61 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -114,7 +114,7 @@
         .collect();
 
     let mut res = Ok(());
-    for param in &impl_generics.params {
+    for param in &impl_generics.own_params {
         match param.kind {
             // Disallow ANY unconstrained type parameters.
             ty::GenericParamDefKind::Type { .. } => {
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index be1be1a..6967cb4 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -212,7 +212,7 @@
             traits::ObligationCause::new(
                 impl1_span,
                 impl1_def_id,
-                traits::ObligationCauseCode::BindingObligation(impl2_node.def_id(), span),
+                traits::ObligationCauseCode::WhereClause(impl2_node.def_id(), span),
             )
         },
     );
@@ -258,23 +258,20 @@
     // unconstrained parameters.
     for (clause, _) in impl_generic_predicates.predicates.iter() {
         if let ty::ClauseKind::Projection(proj) = clause.kind().skip_binder() {
-            let projection_ty = proj.projection_ty;
-            let projected_ty = proj.term;
-
-            let unbound_trait_ref = projection_ty.trait_ref(tcx);
+            let unbound_trait_ref = proj.projection_term.trait_ref(tcx);
             if Some(unbound_trait_ref) == impl_trait_ref {
                 continue;
             }
 
-            unconstrained_parameters.extend(cgp::parameters_for(tcx, projection_ty, true));
+            unconstrained_parameters.extend(cgp::parameters_for(tcx, proj.projection_term, true));
 
-            for param in cgp::parameters_for(tcx, projected_ty, false) {
+            for param in cgp::parameters_for(tcx, proj.term, false) {
                 if !unconstrained_parameters.contains(&param) {
                     constrained_params.insert(param.0);
                 }
             }
 
-            unconstrained_parameters.extend(cgp::parameters_for(tcx, projected_ty, true));
+            unconstrained_parameters.extend(cgp::parameters_for(tcx, proj.term, true));
         }
     }
 
@@ -495,11 +492,11 @@
                     .emit())
             }
         }
-        ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => Err(tcx
+        ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_term, term }) => Err(tcx
             .dcx()
             .struct_span_err(
                 span,
-                format!("cannot specialize on associated type `{projection_ty} == {term}`",),
+                format!("cannot specialize on associated type `{projection_term} == {term}`",),
             )
             .emit()),
         ty::ClauseKind::ConstArgHasType(..) => {
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 66b86c9..d1e50e1 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -75,9 +75,6 @@
 #[macro_use]
 extern crate tracing;
 
-#[macro_use]
-extern crate rustc_middle;
-
 // These are used by Clippy.
 pub mod check;
 
@@ -184,7 +181,7 @@
         let def_kind = tcx.def_kind(item_def_id);
         match def_kind {
             DefKind::Static { .. } => tcx.ensure().eval_static_initializer(item_def_id),
-            DefKind::Const if tcx.generics_of(item_def_id).params.is_empty() => {
+            DefKind::Const if tcx.generics_of(item_def_id).is_empty() => {
                 let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty());
                 let cid = GlobalId { instance, promoted: None };
                 let param_env = ty::ParamEnv::reveal_all();
diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs
index a87112d..97fd773 100644
--- a/compiler/rustc_hir_analysis/src/outlives/mod.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs
@@ -2,7 +2,7 @@
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::GenericArgKind;
-use rustc_middle::ty::{self, CratePredicatesMap, ToPredicate, TyCtxt};
+use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt, Upcast};
 use rustc_span::Span;
 
 mod explicit;
@@ -75,14 +75,14 @@
                         match kind1.unpack() {
                             GenericArgKind::Type(ty1) => Some((
                                 ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty1, *region2))
-                                    .to_predicate(tcx),
+                                    .upcast(tcx),
                                 span,
                             )),
                             GenericArgKind::Lifetime(region1) => Some((
                                 ty::ClauseKind::RegionOutlives(ty::OutlivesPredicate(
                                     region1, *region2,
                                 ))
-                                .to_predicate(tcx),
+                                .upcast(tcx),
                                 span,
                             )),
                             GenericArgKind::Const(_) => {
diff --git a/compiler/rustc_hir_analysis/src/outlives/test.rs b/compiler/rustc_hir_analysis/src/outlives/test.rs
index 60cd8c3..e9b6c67 100644
--- a/compiler/rustc_hir_analysis/src/outlives/test.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/test.rs
@@ -1,3 +1,4 @@
+use rustc_middle::bug;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::{symbol::sym, ErrorGuaranteed};
 
diff --git a/compiler/rustc_hir_analysis/src/outlives/utils.rs b/compiler/rustc_hir_analysis/src/outlives/utils.rs
index d3bb22d..5086c2a 100644
--- a/compiler/rustc_hir_analysis/src/outlives/utils.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/utils.rs
@@ -2,13 +2,14 @@
 use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
 use rustc_middle::ty::{self, Region, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArg, GenericArgKind};
+use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 use smallvec::smallvec;
 
 /// Tracks the `T: 'a` or `'a: 'a` predicates that we have inferred
 /// must be added to the struct header.
 pub(crate) type RequiredPredicates<'tcx> =
-    FxIndexMap<ty::OutlivesPredicate<GenericArg<'tcx>, ty::Region<'tcx>>, Span>;
+    FxIndexMap<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>, Span>;
 
 /// Given a requirement `T: 'a` or `'b: 'a`, deduce the
 /// outlives_component and add it to `required_predicates`
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index dcab571e..9ddba7a 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
@@ -421,7 +421,7 @@
         // We could not gather enough lifetime parameters in the scope.
         // We use the parameter names from the target type's definition instead.
         self.gen_params
-            .params
+            .own_params
             .iter()
             .skip(self.params_offset + self.num_provided_lifetime_args())
             .take(num_params_to_take)
@@ -464,7 +464,7 @@
             })
         };
         self.gen_params
-            .params
+            .own_params
             .iter()
             .skip(self.params_offset + self.num_provided_type_or_const_args())
             .take(num_params_to_take)
@@ -1076,7 +1076,7 @@
             } else {
                 let params = self
                     .gen_params
-                    .params
+                    .own_params
                     .iter()
                     .skip(self.params_offset)
                     .take(bound)
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index eeb8b02..0c436e2 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -8,6 +8,7 @@
 use rustc_hir::def::DefKind;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArgKind, GenericArgsRef};
+use rustc_middle::{bug, span_bug};
 
 use super::terms::VarianceTerm::*;
 use super::terms::*;
@@ -98,7 +99,7 @@
         debug!("build_constraints_for_item({})", tcx.def_path_str(def_id));
 
         // Skip items with no generics - there's nothing to infer in them.
-        if tcx.generics_of(def_id).count() == 0 {
+        if tcx.generics_of(def_id).is_empty() {
             return;
         }
 
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 42885b0..1977451 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -8,6 +8,7 @@
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::query::Providers;
+use rustc_middle::span_bug;
 use rustc_middle::ty::{self, CrateVariancesMap, GenericArgsRef, Ty, TyCtxt};
 use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable};
 
@@ -40,7 +41,7 @@
 
 fn variances_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Variance] {
     // Skip items with no generics - there's nothing to infer in them.
-    if tcx.generics_of(item_def_id).count() == 0 {
+    if tcx.generics_of(item_def_id).is_empty() {
         return &[];
     }
 
@@ -133,7 +134,7 @@
         let mut generics = generics;
         while let Some(def_id) = generics.parent {
             generics = tcx.generics_of(def_id);
-            for param in &generics.params {
+            for param in &generics.own_params {
                 match param.kind {
                     ty::GenericParamDefKind::Lifetime => {
                         variances[param.index as usize] = ty::Bivariant;
@@ -166,7 +167,7 @@
                 }
             }
             ty::ClauseKind::Projection(ty::ProjectionPredicate {
-                projection_ty: ty::AliasTy { args, .. },
+                projection_term: ty::AliasTerm { args, .. },
                 term,
             }) => {
                 for arg in &args[1..] {
diff --git a/compiler/rustc_hir_analysis/src/variance/solve.rs b/compiler/rustc_hir_analysis/src/variance/solve.rs
index 54da327..e64c672 100644
--- a/compiler/rustc_hir_analysis/src/variance/solve.rs
+++ b/compiler/rustc_hir_analysis/src/variance/solve.rs
@@ -76,7 +76,7 @@
         let tcx = self.terms_cx.tcx;
 
         // Make all const parameters invariant.
-        for param in generics.params.iter() {
+        for param in generics.own_params.iter() {
             if let ty::GenericParamDefKind::Const { .. } = param.kind {
                 variances[param.index as usize] = ty::Invariant;
             }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 4f5fbd0..488537e 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -139,8 +139,12 @@
 }
 
 impl<'a> PrintState<'a> for State<'a> {
-    fn comments(&mut self) -> &mut Option<Comments<'a>> {
-        &mut self.comments
+    fn comments(&self) -> Option<&Comments<'a>> {
+        self.comments.as_ref()
+    }
+
+    fn comments_mut(&mut self) -> Option<&mut Comments<'a>> {
+        self.comments.as_mut()
     }
 
     fn ann_post(&mut self, ident: Ident) {
@@ -283,7 +287,7 @@
                 self.pclose();
             }
             hir::TyKind::BareFn(f) => {
-                self.print_ty_fn(f.abi, f.unsafety, f.decl, None, f.generic_params, f.param_names);
+                self.print_ty_fn(f.abi, f.safety, f.decl, None, f.generic_params, f.param_names);
             }
             hir::TyKind::OpaqueDef(..) => self.word("/*impl Trait*/"),
             hir::TyKind::Path(ref qpath) => self.print_qpath(qpath, false),
@@ -347,7 +351,7 @@
                 self.print_fn(
                     decl,
                     hir::FnHeader {
-                        unsafety: hir::Unsafety::Normal,
+                        safety: hir::Safety::Safe,
                         constness: hir::Constness::NotConst,
                         abi: Abi::Rust,
                         asyncness: hir::IsAsync::NotAsync,
@@ -578,7 +582,7 @@
                 self.print_struct(struct_def, generics, item.ident.name, item.span, true);
             }
             hir::ItemKind::Impl(&hir::Impl {
-                unsafety,
+                safety,
                 polarity,
                 defaultness,
                 defaultness_span: _,
@@ -589,7 +593,7 @@
             }) => {
                 self.head("");
                 self.print_defaultness(defaultness);
-                self.print_unsafety(unsafety);
+                self.print_safety(safety);
                 self.word_nbsp("impl");
 
                 if !generics.params.is_empty() {
@@ -618,10 +622,10 @@
                 }
                 self.bclose(item.span);
             }
-            hir::ItemKind::Trait(is_auto, unsafety, generics, bounds, trait_items) => {
+            hir::ItemKind::Trait(is_auto, safety, generics, bounds, trait_items) => {
                 self.head("");
                 self.print_is_auto(is_auto);
-                self.print_unsafety(unsafety);
+                self.print_safety(safety);
                 self.word_nbsp("trait");
                 self.print_ident(item.ident);
                 self.print_generic_params(generics.params);
@@ -1450,7 +1454,7 @@
                     self.word_space(":");
                 }
                 // containing cbox, will be closed by print-block at `}`
-                self.cbox(INDENT_UNIT);
+                self.cbox(0);
                 // head-box, will be closed by print-block after `{`
                 self.ibox(0);
                 self.print_block(blk);
@@ -2230,7 +2234,7 @@
     fn print_ty_fn(
         &mut self,
         abi: Abi,
-        unsafety: hir::Unsafety,
+        safety: hir::Safety,
         decl: &hir::FnDecl<'_>,
         name: Option<Symbol>,
         generic_params: &[hir::GenericParam<'_>],
@@ -2242,7 +2246,7 @@
         self.print_fn(
             decl,
             hir::FnHeader {
-                unsafety,
+                safety,
                 abi,
                 constness: hir::Constness::NotConst,
                 asyncness: hir::IsAsync::NotAsync,
@@ -2263,7 +2267,7 @@
             hir::IsAsync::Async(_) => self.word_nbsp("async"),
         }
 
-        self.print_unsafety(header.unsafety);
+        self.print_safety(header.safety);
 
         if header.abi != Abi::Rust {
             self.word_nbsp("extern");
@@ -2280,10 +2284,10 @@
         }
     }
 
-    fn print_unsafety(&mut self, s: hir::Unsafety) {
+    fn print_safety(&mut self, s: hir::Safety) {
         match s {
-            hir::Unsafety::Normal => {}
-            hir::Unsafety::Unsafe => self.word_nbsp("unsafe"),
+            hir::Safety::Safe => {}
+            hir::Safety::Unsafe => self.word_nbsp("unsafe"),
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 0560d0d..72b95a9 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -46,10 +46,6 @@
 
 hir_typeck_deref_is_empty = this expression `Deref`s to `{$deref_ty}` which implements `is_empty`
 
-hir_typeck_dereferencing_mut_binding = dereferencing `mut` binding
-    .label = `mut` dereferences the type of this binding
-    .help = this will change in edition 2024
-
 hir_typeck_expected_default_return_type = expected `()` because of default return type
 
 hir_typeck_expected_return_type = expected `{$expected}` because of return type
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 4ff6678..c2e62e4 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -5,7 +5,6 @@
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{self as hir, ExprKind, PatKind};
 use rustc_hir_pretty::ty_to_string;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
 use rustc_trait_selection::traits::{
@@ -67,7 +66,7 @@
                 // arm for inconsistent arms or to the whole match when a `()` type
                 // is required).
                 Expectation::ExpectHasType(ety) if ety != tcx.types.unit => ety,
-                _ => self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr.span }),
+                _ => self.next_ty_var(expr.span),
             };
             CoerceMany::with_coercion_sites(coerce_first, arms)
         };
@@ -575,8 +574,7 @@
             // ...but otherwise we want to use any supertype of the
             // scrutinee. This is sort of a workaround, see note (*) in
             // `check_pat` for some details.
-            let scrut_ty =
-                self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: scrut.span });
+            let scrut_ty = self.next_ty_var(scrut.span);
             self.check_expr_has_type_or_error(scrut, scrut_ty, |_| {});
             scrut_ty
         }
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index dfd0b7c..9736c8b 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -9,16 +9,17 @@
 use rustc_hir::def::{self, CtorKind, Namespace, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir_analysis::autoderef::Autoderef;
+use rustc_infer::traits::ObligationCauseCode;
 use rustc_infer::{
     infer,
-    traits::{self, Obligation},
+    traits::{self, Obligation, ObligationCause},
 };
-use rustc_infer::{infer::type_variable::TypeVariableOrigin, traits::ObligationCause};
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
@@ -118,7 +119,11 @@
         };
 
         // we must check that return type of called functions is WF:
-        self.register_wf_obligation(output.into(), call_expr.span, traits::WellFormed(None));
+        self.register_wf_obligation(
+            output.into(),
+            call_expr.span,
+            ObligationCauseCode::WellFormed(None),
+        );
 
         output
     }
@@ -180,14 +185,12 @@
                     infer::FnCall,
                     closure_args.coroutine_closure_sig(),
                 );
-                let tupled_upvars_ty = self
-                    .next_ty_var(TypeVariableOrigin { param_def_id: None, span: callee_expr.span });
+                let tupled_upvars_ty = self.next_ty_var(callee_expr.span);
                 // We may actually receive a coroutine back whose kind is different
                 // from the closure that this dispatched from. This is because when
                 // we have no captures, we automatically implement `FnOnce`. This
                 // impl forces the closure kind to `FnOnce` i.e. `u8`.
-                let kind_ty = self
-                    .next_ty_var(TypeVariableOrigin { param_def_id: None, span: callee_expr.span });
+                let kind_ty = self.next_ty_var(callee_expr.span);
                 let call_sig = self.tcx.mk_fn_sig(
                     [coroutine_closure_sig.tupled_inputs_ty],
                     coroutine_closure_sig.to_coroutine(
@@ -198,7 +201,7 @@
                         tupled_upvars_ty,
                     ),
                     coroutine_closure_sig.c_variadic,
-                    coroutine_closure_sig.unsafety,
+                    coroutine_closure_sig.safety,
                     coroutine_closure_sig.abi,
                 );
                 let adjustments = self.adjust_steps(autoderef);
@@ -298,12 +301,7 @@
             let Some(trait_def_id) = opt_trait_def_id else { continue };
 
             let opt_input_type = opt_arg_exprs.map(|arg_exprs| {
-                Ty::new_tup_from_iter(
-                    self.tcx,
-                    arg_exprs.iter().map(|e| {
-                        self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: e.span })
-                    }),
-                )
+                Ty::new_tup_from_iter(self.tcx, arg_exprs.iter().map(|e| self.next_ty_var(e.span)))
             });
 
             if let Some(ok) = self.lookup_method_in_trait(
@@ -532,9 +530,9 @@
                 self.register_bound(
                     ty,
                     self.tcx.require_lang_item(hir::LangItem::Tuple, Some(sp)),
-                    traits::ObligationCause::new(sp, self.body_id, traits::RustCall),
+                    traits::ObligationCause::new(sp, self.body_id, ObligationCauseCode::RustCall),
                 );
-                self.require_type_is_sized(ty, sp, traits::RustCall);
+                self.require_type_is_sized(ty, sp, ObligationCauseCode::RustCall);
             } else {
                 self.dcx().emit_err(errors::RustCallIncorrectArgs { span: sp });
             }
@@ -577,7 +575,7 @@
                             self.misc(span),
                             self.param_env,
                             ty::ProjectionPredicate {
-                                projection_ty: ty::AliasTy::new(
+                                projection_term: ty::AliasTerm::new(
                                     self.tcx,
                                     fn_once_output_def_id,
                                     [arg_ty.into(), fn_sig.inputs()[0].into(), const_param],
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 92f7428..9e9a1f6 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -36,6 +36,7 @@
 use rustc_errors::{codes::*, Applicability, Diag, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_macros::{TypeFoldable, TypeVisitable};
+use rustc_middle::bug;
 use rustc_middle::mir::Mutability;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::cast::{CastKind, CastTy};
@@ -140,7 +141,10 @@
             | ty::Never
             | ty::Dynamic(_, _, ty::DynStar)
             | ty::Error(_) => {
-                self.dcx().span_bug(span, format!("`{t:?}` should be sized but is not?"));
+                let guar = self
+                    .dcx()
+                    .span_delayed_bug(span, format!("`{t:?}` should be sized but is not?"));
+                return Err(guar);
             }
         })
     }
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index b106eca..843d9e3 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -8,14 +8,12 @@
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir_analysis::check::{check_function_signature, forbid_intrinsic_abi};
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::RegionVariableOrigin;
 use rustc_infer::traits::WellFormedLoc;
 use rustc_middle::ty::{self, Binder, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::sym;
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::traits;
 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
 
 /// Helper used for fns and closures. Does the grungy work of checking a function
@@ -77,7 +75,7 @@
             fcx.register_wf_obligation(
                 param_ty.into(),
                 param.span,
-                traits::WellFormed(Some(WellFormedLoc::Param {
+                ObligationCauseCode::WellFormed(Some(WellFormedLoc::Param {
                     function: fn_def_id,
                     param_idx: idx,
                 })),
@@ -102,7 +100,7 @@
                 param.pat.span,
                 // ty.span == binding_span iff this is a closure parameter with no type ascription,
                 // or if it's an implicit `self` parameter
-                traits::SizedArgumentType(
+                ObligationCauseCode::SizedArgumentType(
                     if ty_span == Some(param.span) && tcx.is_closure_like(fn_def_id.into()) {
                         None
                     } else {
@@ -122,10 +120,18 @@
         hir::FnRetTy::Return(ty) => ty.span,
     };
 
-    fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::SizedReturnType);
+    fcx.require_type_is_sized(
+        declared_ret_ty,
+        return_or_body_span,
+        ObligationCauseCode::SizedReturnType,
+    );
     // We checked the root's signature during wfcheck, but not the child.
     if fcx.tcx.is_typeck_child(fn_def_id.to_def_id()) {
-        fcx.require_type_is_sized(declared_ret_ty, return_or_body_span, traits::WellFormed(None));
+        fcx.require_type_is_sized(
+            declared_ret_ty,
+            return_or_body_span,
+            ObligationCauseCode::WellFormed(None),
+        );
     }
 
     fcx.is_whole_body.set(true);
@@ -142,7 +148,7 @@
         // We have special-cased the case where the function is declared
         // `-> dyn Foo` and we don't actually relate it to the
         // `fcx.ret_coercion`, so just instantiate a type variable.
-        actual_return_ty = fcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span });
+        actual_return_ty = fcx.next_ty_var(span);
         debug!("actual_return_ty replaced with {:?}", actual_return_ty);
     }
 
@@ -210,7 +216,7 @@
         ty::BoundVariableKind::Region(ty::BrAnon),
     ]);
     let expected_sig = ty::Binder::bind_with_vars(
-        tcx.mk_fn_sig([panic_info_ref_ty], tcx.types.never, false, fn_sig.unsafety, Abi::Rust),
+        tcx.mk_fn_sig([panic_info_ref_ty], tcx.types.never, false, fn_sig.safety, Abi::Rust),
         bounds,
     );
 
@@ -233,7 +239,7 @@
     let generic_ty = Ty::new_param(tcx, fn_generic.index, fn_generic.name);
     let main_fn_ty = Ty::new_fn_ptr(
         tcx,
-        Binder::dummy(tcx.mk_fn_sig([], generic_ty, false, hir::Unsafety::Normal, Abi::Rust)),
+        Binder::dummy(tcx.mk_fn_sig([], generic_ty, false, hir::Safety::Safe, Abi::Rust)),
     );
 
     let expected_sig = ty::Binder::dummy(tcx.mk_fn_sig(
@@ -245,7 +251,7 @@
         ],
         tcx.types.isize,
         false,
-        fn_sig.unsafety,
+        fn_sig.safety,
         Abi::Rust,
     ));
 
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 8652692..14a6177 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -6,10 +6,11 @@
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes};
 use rustc_infer::infer::{InferOk, InferResult};
+use rustc_infer::traits::ObligationCauseCode;
 use rustc_macros::{TypeFoldable, TypeVisitable};
+use rustc_middle::span_bug;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
 use rustc_middle::ty::GenericArgs;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
@@ -73,8 +74,7 @@
         let parent_args =
             GenericArgs::identity_for_item(tcx, tcx.typeck_root_def_id(expr_def_id.to_def_id()));
 
-        let tupled_upvars_ty =
-            self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span });
+        let tupled_upvars_ty = self.next_ty_var(expr_span);
 
         // FIXME: We could probably actually just unify this further --
         // instead of having a `FnSig` and a `Option<CoroutineTypes>`,
@@ -89,7 +89,7 @@
                         [Ty::new_tup(tcx, sig.inputs())],
                         sig.output(),
                         sig.c_variadic,
-                        sig.unsafety,
+                        sig.safety,
                         sig.abi,
                     )
                 });
@@ -101,9 +101,7 @@
 
                     // Create a type variable (for now) to represent the closure kind.
                     // It will be unified during the upvar inference phase (`upvar.rs`)
-                    None => {
-                        self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span })
-                    }
+                    None => self.next_ty_var(expr_span),
                 };
 
                 let closure_args = ty::ClosureArgs::new(
@@ -122,11 +120,12 @@
                 let yield_ty = match kind {
                     hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)
                     | hir::CoroutineKind::Coroutine(_) => {
-                        let yield_ty = self.next_ty_var(TypeVariableOrigin {
-                            param_def_id: None,
-                            span: expr_span,
-                        });
-                        self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType);
+                        let yield_ty = self.next_ty_var(expr_span);
+                        self.require_type_is_sized(
+                            yield_ty,
+                            expr_span,
+                            ObligationCauseCode::SizedYieldType,
+                        );
                         yield_ty
                     }
                     // HACK(-Ztrait-solver=next): In the *old* trait solver, we must eagerly
@@ -134,11 +133,12 @@
                     // in this block in projection correctly. In the new trait solver, it is
                     // not a problem.
                     hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::AsyncGen, _) => {
-                        let yield_ty = self.next_ty_var(TypeVariableOrigin {
-                            param_def_id: None,
-                            span: expr_span,
-                        });
-                        self.require_type_is_sized(yield_ty, expr_span, traits::SizedYieldType);
+                        let yield_ty = self.next_ty_var(expr_span);
+                        self.require_type_is_sized(
+                            yield_ty,
+                            expr_span,
+                            ObligationCauseCode::SizedYieldType,
+                        );
 
                         Ty::new_adt(
                             tcx,
@@ -163,8 +163,7 @@
                 // Resume type defaults to `()` if the coroutine has no argument.
                 let resume_ty = liberated_sig.inputs().get(0).copied().unwrap_or(tcx.types.unit);
 
-                let interior =
-                    self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span });
+                let interior = self.next_ty_var(expr_span);
                 self.deferred_coroutine_interiors.borrow_mut().push((
                     expr_def_id,
                     body.id(),
@@ -177,7 +176,7 @@
                 // ty of `().`
                 let kind_ty = match kind {
                     hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) => {
-                        self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span })
+                        self.next_ty_var(expr_span)
                     }
                     _ => tcx.types.unit,
                 };
@@ -212,23 +211,18 @@
                     }
                 };
                 // Compute all of the variables that will be used to populate the coroutine.
-                let resume_ty =
-                    self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span });
-                let interior =
-                    self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span });
+                let resume_ty = self.next_ty_var(expr_span);
+                let interior = self.next_ty_var(expr_span);
 
                 let closure_kind_ty = match expected_kind {
                     Some(kind) => Ty::from_closure_kind(tcx, kind),
 
                     // Create a type variable (for now) to represent the closure kind.
                     // It will be unified during the upvar inference phase (`upvar.rs`)
-                    None => {
-                        self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span })
-                    }
+                    None => self.next_ty_var(expr_span),
                 };
 
-                let coroutine_captures_by_ref_ty =
-                    self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span });
+                let coroutine_captures_by_ref_ty = self.next_ty_var(expr_span);
                 let closure_args = ty::CoroutineClosureArgs::new(
                     tcx,
                     ty::CoroutineClosureArgsParts {
@@ -244,7 +238,7 @@
                                     ],
                                     Ty::new_tup(tcx, &[bound_yield_ty, bound_return_ty]),
                                     sig.c_variadic,
-                                    sig.unsafety,
+                                    sig.safety,
                                     sig.abi,
                                 )
                             }),
@@ -260,13 +254,10 @@
 
                     // Create a type variable (for now) to represent the closure kind.
                     // It will be unified during the upvar inference phase (`upvar.rs`)
-                    None => {
-                        self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span })
-                    }
+                    None => self.next_ty_var(expr_span),
                 };
 
-                let coroutine_upvars_ty =
-                    self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr_span });
+                let coroutine_upvars_ty = self.next_ty_var(expr_span);
 
                 // We need to turn the liberated signature that we got from HIR, which
                 // looks something like `|Args...| -> T`, into a signature that is suitable
@@ -290,7 +281,7 @@
                     liberated_sig.inputs().iter().copied(),
                     coroutine_output_ty,
                     liberated_sig.c_variadic,
-                    liberated_sig.unsafety,
+                    liberated_sig.safety,
                     liberated_sig.abi,
                 );
 
@@ -424,7 +415,7 @@
             // many viable options, so pick the most restrictive.
             let trait_def_id = match bound_predicate.skip_binder() {
                 ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
-                    Some(data.projection_ty.trait_def_id(self.tcx))
+                    Some(data.projection_term.trait_def_id(self.tcx))
                 }
                 ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => Some(data.def_id()),
                 _ => None,
@@ -485,7 +476,7 @@
             _ => return None,
         }
 
-        let arg_param_ty = projection.skip_binder().projection_ty.args.type_at(1);
+        let arg_param_ty = projection.skip_binder().projection_term.args.type_at(1);
         let arg_param_ty = self.resolve_vars_if_possible(arg_param_ty);
         debug!(?arg_param_ty);
 
@@ -502,7 +493,7 @@
             input_tys,
             ret_param_ty,
             false,
-            hir::Unsafety::Normal,
+            hir::Safety::Safe,
             Abi::Rust,
         ));
 
@@ -614,7 +605,7 @@
                 sig.inputs().iter().cloned(),
                 sig.output(),
                 sig.c_variadic,
-                hir::Unsafety::Normal,
+                hir::Safety::Safe,
                 Abi::RustCall,
             )
         });
@@ -752,7 +743,7 @@
                 inputs,
                 supplied_output_ty,
                 expected_sigs.liberated_sig.c_variadic,
-                hir::Unsafety::Normal,
+                hir::Safety::Safe,
                 Abi::RustCall,
             );
 
@@ -829,7 +820,7 @@
                 supplied_arguments,
                 supplied_return,
                 decl.c_variadic,
-                hir::Unsafety::Normal,
+                hir::Safety::Safe,
                 Abi::RustCall,
             ),
             bound_vars,
@@ -940,7 +931,7 @@
         };
 
         // Check that this is a projection from the `Future` trait.
-        let trait_def_id = predicate.projection_ty.trait_def_id(self.tcx);
+        let trait_def_id = predicate.projection_term.trait_def_id(self.tcx);
         let future_trait = self.tcx.require_lang_item(LangItem::Future, Some(cause_span));
         if trait_def_id != future_trait {
             debug!("deduce_future_output_from_projection: not a future");
@@ -950,11 +941,11 @@
         // The `Future` trait has only one associated item, `Output`,
         // so check that this is what we see.
         let output_assoc_item = self.tcx.associated_item_def_ids(future_trait)[0];
-        if output_assoc_item != predicate.projection_ty.def_id {
+        if output_assoc_item != predicate.projection_term.def_id {
             span_bug!(
                 cause_span,
                 "projecting associated item `{:?}` from future, which is not Output `{:?}`",
-                predicate.projection_ty.def_id,
+                predicate.projection_term.def_id,
                 output_assoc_item,
             );
         }
@@ -993,7 +984,7 @@
             supplied_arguments,
             err_ty,
             decl.c_variadic,
-            hir::Unsafety::Normal,
+            hir::Safety::Safe,
             Abi::RustCall,
         ));
 
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index df92af8..33c2443 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -41,11 +41,11 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::{Coercion, DefineOpaqueTypes, InferOk, InferResult};
 use rustc_infer::traits::{IfExpressionCause, MatchExpressionArmCause};
 use rustc_infer::traits::{Obligation, PredicateObligation};
 use rustc_middle::lint::in_external_macro;
+use rustc_middle::span_bug;
 use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, PointerCoercion,
@@ -257,11 +257,7 @@
 
         if b.is_ty_var() {
             // Two unresolved type variables: create a `Coerce` predicate.
-            let target_ty = if self.use_lub {
-                self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: self.cause.span })
-            } else {
-                b
-            };
+            let target_ty = if self.use_lub { self.next_ty_var(self.cause.span) } else { b };
 
             let mut obligations = Vec::with_capacity(2);
             for &source_ty in &[a, b] {
@@ -557,8 +553,7 @@
         // the `CoerceUnsized` target type and the expected type.
         // We only have the latter, so we use an inference variable
         // for the former and let type inference do the rest.
-        let origin = TypeVariableOrigin { param_def_id: None, span: self.cause.span };
-        let coerce_target = self.next_ty_var(origin);
+        let coerce_target = self.next_ty_var(self.cause.span);
         let mut coercion = self.unify_and(coerce_target, target, |target| {
             let unsize = Adjustment { kind: Adjust::Pointer(PointerCoercion::Unsize), target };
             match reborrow {
@@ -764,10 +759,9 @@
             self.tcx,
             self.cause.clone(),
             self.param_env,
-            ty::TraitRef::from_lang_item(
+            ty::TraitRef::new(
                 self.tcx,
-                hir::LangItem::PointerLike,
-                self.cause.span,
+                self.tcx.require_lang_item(hir::LangItem::PointerLike, Some(self.cause.span)),
                 [a],
             ),
         ));
@@ -794,8 +788,8 @@
             let outer_universe = self.infcx.universe();
 
             let result = if let ty::FnPtr(fn_ty_b) = b.kind()
-                && let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) =
-                    (fn_ty_a.unsafety(), fn_ty_b.unsafety())
+                && let (hir::Safety::Safe, hir::Safety::Unsafe) =
+                    (fn_ty_a.safety(), fn_ty_b.safety())
             {
                 let unsafe_a = self.tcx.safe_to_unsafe_fn_ty(fn_ty_a);
                 self.unify_and(unsafe_a, b, to_unsafe)
@@ -857,7 +851,7 @@
 
                     // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396).
 
-                    if b_sig.unsafety() == hir::Unsafety::Normal
+                    if b_sig.safety() == hir::Safety::Safe
                         && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty()
                     {
                         return Err(TypeError::TargetFeatureCast(def_id));
@@ -928,14 +922,14 @@
                 // or
                 //     `unsafe fn(arg0,arg1,...) -> _`
                 let closure_sig = args_a.as_closure().sig();
-                let unsafety = fn_ty.unsafety();
+                let safety = fn_ty.safety();
                 let pointer_ty =
-                    Ty::new_fn_ptr(self.tcx, self.tcx.signature_unclosure(closure_sig, unsafety));
+                    Ty::new_fn_ptr(self.tcx, self.tcx.signature_unclosure(closure_sig, safety));
                 debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty);
                 self.unify_and(
                     pointer_ty,
                     b,
-                    simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(unsafety))),
+                    simple(Adjust::Pointer(PointerCoercion::ClosureFnPointer(safety))),
                 )
             }
             _ => self.unify_and(a, b, identity),
@@ -1132,27 +1126,25 @@
                     (ty::Closure(_, args), ty::FnDef(..)) => {
                         let b_sig = new_ty.fn_sig(self.tcx);
                         let a_sig =
-                            self.tcx.signature_unclosure(args.as_closure().sig(), b_sig.unsafety());
+                            self.tcx.signature_unclosure(args.as_closure().sig(), b_sig.safety());
                         (Some(a_sig), Some(b_sig))
                     }
                     (ty::FnDef(..), ty::Closure(_, args)) => {
                         let a_sig = prev_ty.fn_sig(self.tcx);
                         let b_sig =
-                            self.tcx.signature_unclosure(args.as_closure().sig(), a_sig.unsafety());
+                            self.tcx.signature_unclosure(args.as_closure().sig(), a_sig.safety());
                         (Some(a_sig), Some(b_sig))
                     }
-                    (ty::Closure(_, args_a), ty::Closure(_, args_b)) => {
-                        (
-                            Some(self.tcx.signature_unclosure(
-                                args_a.as_closure().sig(),
-                                hir::Unsafety::Normal,
-                            )),
-                            Some(self.tcx.signature_unclosure(
-                                args_b.as_closure().sig(),
-                                hir::Unsafety::Normal,
-                            )),
-                        )
-                    }
+                    (ty::Closure(_, args_a), ty::Closure(_, args_b)) => (
+                        Some(
+                            self.tcx
+                                .signature_unclosure(args_a.as_closure().sig(), hir::Safety::Safe),
+                        ),
+                        Some(
+                            self.tcx
+                                .signature_unclosure(args_b.as_closure().sig(), hir::Safety::Safe),
+                        ),
+                    ),
                     _ => (None, None),
                 }
             }
@@ -1174,14 +1166,14 @@
             let fn_ptr = Ty::new_fn_ptr(self.tcx, sig);
             let prev_adjustment = match prev_ty.kind() {
                 ty::Closure(..) => {
-                    Adjust::Pointer(PointerCoercion::ClosureFnPointer(a_sig.unsafety()))
+                    Adjust::Pointer(PointerCoercion::ClosureFnPointer(a_sig.safety()))
                 }
                 ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer),
                 _ => span_bug!(cause.span, "should not try to coerce a {prev_ty} to a fn pointer"),
             };
             let next_adjustment = match new_ty.kind() {
                 ty::Closure(..) => {
-                    Adjust::Pointer(PointerCoercion::ClosureFnPointer(b_sig.unsafety()))
+                    Adjust::Pointer(PointerCoercion::ClosureFnPointer(b_sig.safety()))
                 }
                 ty::FnDef(..) => Adjust::Pointer(PointerCoercion::ReifyFnPointer),
                 _ => span_bug!(new.span, "should not try to coerce a {new_ty} to a fn pointer"),
@@ -1599,31 +1591,28 @@
                         err.span_label(cause.span, "return type is not `()`");
                     }
                     ObligationCauseCode::BlockTailExpression(blk_id, ..) => {
-                        let parent_id = fcx.tcx.parent_hir_id(blk_id);
                         err = self.report_return_mismatched_types(
                             cause,
                             expected,
                             found,
                             coercion_error,
                             fcx,
-                            parent_id,
+                            blk_id,
                             expression,
-                            Some(blk_id),
                         );
                         if !fcx.tcx.features().unsized_locals {
                             unsized_return = self.is_return_ty_definitely_unsized(fcx);
                         }
                     }
-                    ObligationCauseCode::ReturnValue(id) => {
+                    ObligationCauseCode::ReturnValue(return_expr_id) => {
                         err = self.report_return_mismatched_types(
                             cause,
                             expected,
                             found,
                             coercion_error,
                             fcx,
-                            id,
+                            return_expr_id,
                             expression,
-                            None,
                         );
                         if !fcx.tcx.features().unsized_locals {
                             unsized_return = self.is_return_ty_definitely_unsized(fcx);
@@ -1817,13 +1806,14 @@
         found: Ty<'tcx>,
         ty_err: TypeError<'tcx>,
         fcx: &FnCtxt<'a, 'tcx>,
-        id: hir::HirId,
+        block_or_return_id: hir::HirId,
         expression: Option<&'tcx hir::Expr<'tcx>>,
-        blk_id: Option<hir::HirId>,
     ) -> Diag<'a> {
         let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
 
-        let parent_id = fcx.tcx.parent_hir_id(id);
+        let due_to_block = matches!(fcx.tcx.hir_node(block_or_return_id), hir::Node::Block(..));
+
+        let parent_id = fcx.tcx.parent_hir_id(block_or_return_id);
         let parent = fcx.tcx.hir_node(parent_id);
         if let Some(expr) = expression
             && let hir::Node::Expr(hir::Expr {
@@ -1837,72 +1827,64 @@
         // Verify that this is a tail expression of a function, otherwise the
         // label pointing out the cause for the type coercion will be wrong
         // as prior return coercions would not be relevant (#57664).
-        let fn_decl = if let (Some(expr), Some(blk_id)) = (expression, blk_id) {
+        if let Some(expr) = expression
+            && due_to_block
+        {
             fcx.suggest_missing_semicolon(&mut err, expr, expected, false);
-            let pointing_at_return_type =
-                fcx.suggest_mismatched_types_on_tail(&mut err, expr, expected, found, blk_id);
-            if let (Some(cond_expr), true, false) = (
-                fcx.tcx.hir().get_if_cause(expr.hir_id),
-                expected.is_unit(),
-                pointing_at_return_type,
-            )
+            let pointing_at_return_type = fcx.suggest_mismatched_types_on_tail(
+                &mut err,
+                expr,
+                expected,
+                found,
+                block_or_return_id,
+            );
+            if let Some(cond_expr) = fcx.tcx.hir().get_if_cause(expr.hir_id)
+                && expected.is_unit()
+                && !pointing_at_return_type
                 // If the block is from an external macro or try (`?`) desugaring, then
                 // do not suggest adding a semicolon, because there's nowhere to put it.
                 // See issues #81943 and #87051.
                 && matches!(
                     cond_expr.span.desugaring_kind(),
                     None | Some(DesugaringKind::WhileLoop)
-                ) && !in_external_macro(fcx.tcx.sess, cond_expr.span)
-                    && !matches!(
-                        cond_expr.kind,
-                        hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_))
-                    )
+                )
+                && !in_external_macro(fcx.tcx.sess, cond_expr.span)
+                && !matches!(
+                    cond_expr.kind,
+                    hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_))
+                )
             {
                 err.span_label(cond_expr.span, "expected this to be `()`");
                 if expr.can_have_side_effects() {
                     fcx.suggest_semicolon_at_end(cond_expr.span, &mut err);
                 }
             }
-            fcx.get_node_fn_decl(parent)
-                .map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
-        } else {
-            fcx.get_fn_decl(parent_id)
         };
 
-        if let Some((fn_id, fn_decl, can_suggest)) = fn_decl {
-            if blk_id.is_none() {
-                fcx.suggest_missing_return_type(
-                    &mut err,
-                    fn_decl,
-                    expected,
-                    found,
-                    can_suggest,
-                    fn_id,
-                );
-            }
+        // If this is due to an explicit `return`, suggest adding a return type.
+        if let Some((fn_id, fn_decl, can_suggest)) = fcx.get_fn_decl(parent_id)
+            && !due_to_block
+        {
+            fcx.suggest_missing_return_type(&mut err, fn_decl, expected, found, can_suggest, fn_id);
         }
 
-        let mut parent_id = fcx.tcx.hir().get_parent_item(id).def_id;
-        let mut parent_item = fcx.tcx.hir_node_by_def_id(parent_id);
-        // When suggesting return, we need to account for closures and async blocks, not just items.
-        for (_, node) in fcx.tcx.hir().parent_iter(id) {
-            match node {
-                hir::Node::Expr(&hir::Expr {
-                    kind: hir::ExprKind::Closure(hir::Closure { def_id, .. }),
-                    ..
-                }) => {
-                    parent_item = node;
-                    parent_id = *def_id;
-                    break;
-                }
-                hir::Node::Item(_) | hir::Node::TraitItem(_) | hir::Node::ImplItem(_) => break,
-                _ => {}
-            }
-        }
-
-        if let (Some(expr), Some(_), Some(fn_decl)) = (expression, blk_id, parent_item.fn_decl()) {
+        // If this is due to a block, then maybe we forgot a `return`/`break`.
+        if due_to_block
+            && let Some(expr) = expression
+            && let Some((parent_fn_decl, parent_id)) = fcx
+                .tcx
+                .hir()
+                .parent_iter(block_or_return_id)
+                .find_map(|(_, node)| Some((node.fn_decl()?, node.associated_body()?.0)))
+        {
             fcx.suggest_missing_break_or_return_expr(
-                &mut err, expr, fn_decl, expected, found, id, parent_id,
+                &mut err,
+                expr,
+                parent_fn_decl,
+                expected,
+                found,
+                block_or_return_id,
+                parent_id,
             );
         }
 
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 60c0b18..7916366 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -5,6 +5,7 @@
 use rustc_hir::def::Res;
 use rustc_hir::intravisit::Visitor;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
+use rustc_middle::bug;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::BottomUpFolder;
@@ -330,16 +331,13 @@
             hir.body(hir.maybe_body_owned_by(self.body_id).expect("expected item to have body"));
         expr_finder.visit_expr(body.value);
 
-        use rustc_infer::infer::type_variable::*;
-        use rustc_middle::infer::unify_key::*;
         // Replaces all of the variables in the given type with a fresh inference variable.
         let mut fudger = BottomUpFolder {
             tcx: self.tcx,
             ty_op: |ty| {
                 if let ty::Infer(infer) = ty.kind() {
                     match infer {
-                        ty::TyVar(_) => self
-                            .next_ty_var(TypeVariableOrigin { param_def_id: None, span: DUMMY_SP }),
+                        ty::TyVar(_) => self.next_ty_var(DUMMY_SP),
                         ty::IntVar(_) => self.next_int_var(),
                         ty::FloatVar(_) => self.next_float_var(),
                         ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
@@ -353,10 +351,7 @@
             lt_op: |_| self.tcx.lifetimes.re_erased,
             ct_op: |ct| {
                 if let ty::ConstKind::Infer(_) = ct.kind() {
-                    self.next_const_var(
-                        ct.ty(),
-                        ConstVariableOrigin { param_def_id: None, span: DUMMY_SP },
-                    )
+                    self.next_const_var(ct.ty(), DUMMY_SP)
                 } else {
                     ct
                 }
@@ -378,8 +373,11 @@
                 let Some(arg_ty) = self.node_ty_opt(args[idx].hir_id) else {
                     return false;
                 };
-                let possible_rcvr_ty = expr_finder.uses.iter().find_map(|binding| {
+                let possible_rcvr_ty = expr_finder.uses.iter().rev().find_map(|binding| {
                     let possible_rcvr_ty = self.node_ty_opt(binding.hir_id)?;
+                    if possible_rcvr_ty.is_ty_var() {
+                        return None;
+                    }
                     // Fudge the receiver, so we can do new inference on it.
                     let possible_rcvr_ty = possible_rcvr_ty.fold_with(&mut fudger);
                     let method = self
@@ -391,6 +389,12 @@
                             binding,
                         )
                         .ok()?;
+                    // Make sure we select the same method that we started with...
+                    if Some(method.def_id)
+                        != self.typeck_results.borrow().type_dependent_def_id(call_expr.hir_id)
+                    {
+                        return None;
+                    }
                     // Unify the method signature with our incompatible arg, to
                     // do inference in the *opposite* direction and to find out
                     // what our ideal rcvr ty would look like.
@@ -461,6 +465,12 @@
                 ) else {
                     continue;
                 };
+                // Make sure we select the same method that we started with...
+                if Some(method.def_id)
+                    != self.typeck_results.borrow().type_dependent_def_id(parent_expr.hir_id)
+                {
+                    continue;
+                }
 
                 let ideal_rcvr_ty = rcvr_ty.fold_with(&mut fudger);
                 let ideal_method = self
@@ -510,13 +520,19 @@
                     // blame arg, if possible. Don't do this if we're coming from
                     // arg mismatch code, because we'll possibly suggest a mutually
                     // incompatible fix at the original mismatch site.
+                    // HACK(compiler-errors): We don't actually consider the implications
+                    // of our inference guesses in `emit_type_mismatch_suggestions`, so
+                    // only suggest things when we know our type error is precisely due to
+                    // a type mismatch, and not via some projection or something. See #116155.
                     if matches!(source, TypeMismatchSource::Ty(_))
                         && let Some(ideal_method) = ideal_method
-                        && let ideal_arg_ty = self.resolve_vars_if_possible(ideal_method.sig.inputs()[idx + 1])
-                        // HACK(compiler-errors): We don't actually consider the implications
-                        // of our inference guesses in `emit_type_mismatch_suggestions`, so
-                        // only suggest things when we know our type error is precisely due to
-                        // a type mismatch, and not via some projection or something. See #116155.
+                        && Some(ideal_method.def_id)
+                            == self
+                                .typeck_results
+                                .borrow()
+                                .type_dependent_def_id(parent_expr.hir_id)
+                        && let ideal_arg_ty =
+                            self.resolve_vars_if_possible(ideal_method.sig.inputs()[idx + 1])
                         && !ideal_arg_ty.has_non_region_infer()
                     {
                         self.emit_type_mismatch_suggestions(
@@ -943,14 +959,14 @@
         );
     }
 
-    pub fn get_conversion_methods(
+    pub fn get_conversion_methods_for_diagnostic(
         &self,
         span: Span,
         expected: Ty<'tcx>,
         checked_ty: Ty<'tcx>,
         hir_id: hir::HirId,
     ) -> Vec<AssocItem> {
-        let methods = self.probe_for_return_type(
+        let methods = self.probe_for_return_type_for_diagnostic(
             span,
             probe::Mode::MethodCall,
             expected,
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index ba8f246..f250b90 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -651,10 +651,3 @@
         ends: Vec<Span>,
     },
 }
-#[derive(LintDiagnostic)]
-#[diag(hir_typeck_dereferencing_mut_binding)]
-pub struct DereferencingMutBinding {
-    #[label]
-    #[help]
-    pub span: Span,
-}
diff --git a/compiler/rustc_hir_typeck/src/expectation.rs b/compiler/rustc_hir_typeck/src/expectation.rs
index 5106d29..91deae4 100644
--- a/compiler/rustc_hir_typeck/src/expectation.rs
+++ b/compiler/rustc_hir_typeck/src/expectation.rs
@@ -1,4 +1,3 @@
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
 
@@ -110,7 +109,6 @@
     /// Like `only_has_type`, but instead of returning `None` if no
     /// hard constraint exists, creates a fresh type variable.
     pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> {
-        self.only_has_type(fcx)
-            .unwrap_or_else(|| fcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span }))
+        self.only_has_type(fcx).unwrap_or_else(|| fcx.next_ty_var(span))
     }
 }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 7b552bb..fade943 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -37,7 +37,6 @@
 use rustc_hir::{ExprKind, HirId, QPath};
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer as _;
 use rustc_infer::infer;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::infer::InferOk;
 use rustc_infer::traits::query::NoSolution;
@@ -46,6 +45,7 @@
 use rustc_middle::ty::error::{ExpectedFound, TypeError::Sorts};
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, AdtKind, Ty, TypeVisitableExt};
+use rustc_middle::{bug, span_bug};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_session::parse::feature_err;
 use rustc_span::edit_distance::find_best_match_for_name;
@@ -80,8 +80,7 @@
                 return Ty::new_error(self.tcx(), reported);
             }
 
-            let adj_ty =
-                self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr.span });
+            let adj_ty = self.next_ty_var(expr.span);
             self.apply_adjustments(
                 expr,
                 vec![Adjustment { kind: Adjust::NeverToAny, target: adj_ty }],
@@ -575,7 +574,7 @@
                     self.require_type_is_sized_deferred(
                         input,
                         span,
-                        traits::SizedArgumentType(None),
+                        ObligationCauseCode::SizedArgumentType(None),
                     );
                 }
             }
@@ -593,7 +592,7 @@
             self.require_type_is_sized_deferred(
                 output,
                 call.map_or(expr.span, |e| e.span),
-                traits::SizedCallReturnType,
+                ObligationCauseCode::SizedCallReturnType,
             );
         }
 
@@ -1251,7 +1250,7 @@
             }
         });
 
-        self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized);
+        self.require_type_is_sized(lhs_ty, lhs.span, ObligationCauseCode::AssignmentLhsSized);
 
         if let Err(guar) = (lhs_ty, rhs_ty).error_reported() {
             Ty::new_error(self.tcx, guar)
@@ -1271,7 +1270,7 @@
         // otherwise check exactly as a let statement
         self.check_decl((let_expr, hir_id).into());
         // but return a bool, for this is a boolean expression
-        if let Some(error_guaranteed) = let_expr.is_recovered {
+        if let ast::Recovered::Yes(error_guaranteed) = let_expr.recovered {
             self.set_tainted_by_errors(error_guaranteed);
             Ty::new_error(self.tcx, error_guaranteed)
         } else {
@@ -1347,6 +1346,7 @@
                 if segment.ident.name != kw::Empty {
                     if let Some(err) = self.report_method_error(
                         span,
+                        Some(rcvr),
                         rcvr_t,
                         segment.ident,
                         SelfSource::MethodCall(rcvr),
@@ -1412,9 +1412,7 @@
                     ty::Array(ty, _) | ty::Slice(ty) => Some(ty),
                     _ => None,
                 })
-                .unwrap_or_else(|| {
-                    self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr.span })
-                });
+                .unwrap_or_else(|| self.next_ty_var(expr.span));
             let mut coerce = CoerceMany::with_coercion_sites(coerce_to, args);
             assert_eq!(self.diverges.get(), Diverges::Maybe);
             for e in args {
@@ -1424,7 +1422,7 @@
             }
             coerce.complete(self)
         } else {
-            self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: expr.span })
+            self.next_ty_var(expr.span)
         };
         let array_len = args.len() as u64;
         self.suggest_array_len(expr, array_len);
@@ -1475,7 +1473,7 @@
         crate::GatherLocalsVisitor::new(&fcx).visit_body(body);
 
         let ty = fcx.check_expr_with_expectation(body.value, expected);
-        fcx.require_type_is_sized(ty, body.value.span, traits::ConstSized);
+        fcx.require_type_is_sized(ty, body.value.span, ObligationCauseCode::ConstSized);
         fcx.write_ty(block.hir_id, ty);
         ty
     }
@@ -1507,8 +1505,7 @@
                 (uty, uty)
             }
             None => {
-                let ty =
-                    self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: element.span });
+                let ty = self.next_ty_var(element.span);
                 let element_ty = self.check_expr_has_type_or_error(element, ty, |_| {});
                 (element_ty, ty)
             }
@@ -1522,7 +1519,7 @@
 
         let ty = Ty::new_array_with_const_len(tcx, t, count);
 
-        self.register_wf_obligation(ty.into(), expr.span, traits::WellFormed(None));
+        self.register_wf_obligation(ty.into(), expr.span, ObligationCauseCode::WellFormed(None));
 
         ty
     }
@@ -1612,7 +1609,11 @@
         if let Err(guar) = tuple.error_reported() {
             Ty::new_error(self.tcx, guar)
         } else {
-            self.require_type_is_sized(tuple, expr.span, traits::TupleInitializerSized);
+            self.require_type_is_sized(
+                tuple,
+                expr.span,
+                ObligationCauseCode::TupleInitializerSized,
+            );
             tuple
         }
     }
@@ -1651,7 +1652,7 @@
             base_expr,
         );
 
-        self.require_type_is_sized(adt_ty, expr.span, traits::StructInitializerSized);
+        self.require_type_is_sized(adt_ty, expr.span, ObligationCauseCode::StructInitializerSized);
         adt_ty
     }
 
@@ -2414,7 +2415,12 @@
 
         let guar = if field.name == kw::Empty {
             self.dcx().span_delayed_bug(field.span, "field name with no name")
-        } else if self.method_exists(field, base_ty, expr.hir_id, expected.only_has_type(self)) {
+        } else if self.method_exists_for_diagnostic(
+            field,
+            base_ty,
+            expr.hir_id,
+            expected.only_has_type(self),
+        ) {
             self.ban_take_value_of_method(expr, base_ty, field)
         } else if !base_ty.is_primitive_ty() {
             self.ban_nonexisting_field(field, base, expr, base_ty)
@@ -2600,7 +2606,7 @@
         let mut err = self.private_field_err(field, base_did);
 
         // Also check if an accessible method exists, which is often what is meant.
-        if self.method_exists(field, expr_t, expr.hir_id, return_ty)
+        if self.method_exists_for_diagnostic(field, expr_t, expr.hir_id, return_ty)
             && !self.expr_in_place(expr.hir_id)
         {
             self.suggest_method_call(
@@ -3084,14 +3090,12 @@
                             polarity: ty::PredicatePolarity::Positive,
                         }),
                         |derived| {
-                            traits::ImplDerivedObligation(Box::new(
-                                traits::ImplDerivedObligationCause {
-                                    derived,
-                                    impl_or_alias_def_id: impl_def_id,
-                                    impl_def_predicate_index: Some(idx),
-                                    span,
-                                },
-                            ))
+                            ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause {
+                                derived,
+                                impl_or_alias_def_id: impl_def_id,
+                                impl_def_predicate_index: Some(idx),
+                                span,
+                            }))
                         },
                     )
                 },
@@ -3109,7 +3113,7 @@
 
             let true_errors = ocx.select_where_possible();
 
-            // Do a leak check -- we can't really report report a useful error here,
+            // Do a leak check -- we can't really report a useful error here,
             // but it at least avoids an ICE when the error has to do with higher-ranked
             // lifetimes.
             self.leak_check(outer_universe, Some(snapshot))?;
@@ -3182,7 +3186,7 @@
     fn check_expr_asm_operand(&self, expr: &'tcx hir::Expr<'tcx>, is_input: bool) {
         let needs = if is_input { Needs::None } else { Needs::MutPlace };
         let ty = self.check_expr_with_needs(expr, needs);
-        self.require_type_is_sized(ty, expr.span, traits::InlineAsmSized);
+        self.require_type_is_sized(ty, expr.span, ObligationCauseCode::InlineAsmSized);
 
         if !is_input && !expr.is_syntactic_place_expr() {
             self.dcx()
@@ -3353,7 +3357,7 @@
                     let field_ty = self.field_ty(expr.span, field, args);
 
                     // FIXME: DSTs with static alignment should be allowed
-                    self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation);
+                    self.require_type_is_sized(field_ty, expr.span, ObligationCauseCode::Misc);
 
                     if field.vis.is_accessible_from(sub_def_scope, self.tcx) {
                         self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
@@ -3381,7 +3385,7 @@
                         let field_ty = self.field_ty(expr.span, field, args);
 
                         // FIXME: DSTs with static alignment should be allowed
-                        self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation);
+                        self.require_type_is_sized(field_ty, expr.span, ObligationCauseCode::Misc);
 
                         if field.vis.is_accessible_from(def_scope, self.tcx) {
                             self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
@@ -3402,7 +3406,7 @@
                         && field.name == sym::integer(index)
                     {
                         for ty in tys.iter().take(index + 1) {
-                            self.require_type_is_sized(ty, expr.span, traits::MiscObligation);
+                            self.require_type_is_sized(ty, expr.span, ObligationCauseCode::Misc);
                         }
                         if let Some(&field_ty) = tys.get(index) {
                             field_indices.push((FIRST_VARIANT, index.into()));
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index cc42e69..89f6257 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -2,26 +2,34 @@
 //! normal visitor, which just walks the entire body in one shot, the
 //! `ExprUseVisitor` determines how expressions are being used.
 
+use std::cell::{Ref, RefCell};
+use std::ops::Deref;
 use std::slice::from_ref;
 
 use hir::def::DefKind;
+use hir::pat_util::EnumerateAndAdjustIterator as _;
 use hir::Expr;
+use rustc_lint::LateContext;
 // Export these here so that Clippy can use them.
 pub use rustc_middle::hir::place::{Place, PlaceBase, PlaceWithHirId, Projection};
 
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_hir as hir;
-use rustc_hir::def::Res;
+use rustc_hir::def::{CtorOf, Res};
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{HirId, PatKind};
-use rustc_infer::infer::InferCtxt;
 use rustc_middle::hir::place::ProjectionKind;
 use rustc_middle::mir::FakeReadCause;
-use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt};
-use rustc_target::abi::FIRST_VARIANT;
+use rustc_middle::ty::{
+    self, adjustment, AdtKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt as _,
+};
+use rustc_middle::{bug, span_bug};
+use rustc_span::{ErrorGuaranteed, Span};
+use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
+use rustc_trait_selection::infer::InferCtxtExt;
 use ty::BorrowKind::ImmBorrow;
 
-use crate::mem_categorization as mc;
+use crate::fn_ctxt::FnCtxt;
 
 /// This trait defines the callbacks you can expect to receive when
 /// employing the ExprUseVisitor.
@@ -80,191 +88,322 @@
     );
 }
 
-#[derive(Copy, Clone, PartialEq, Debug)]
-enum ConsumeMode {
-    /// reference to x where x has a type that copies
-    Copy,
-    /// reference to x where x has a type that moves
-    Move,
+impl<'tcx, D: Delegate<'tcx>> Delegate<'tcx> for &mut D {
+    fn consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
+        (**self).consume(place_with_id, diag_expr_id)
+    }
+
+    fn borrow(
+        &mut self,
+        place_with_id: &PlaceWithHirId<'tcx>,
+        diag_expr_id: HirId,
+        bk: ty::BorrowKind,
+    ) {
+        (**self).borrow(place_with_id, diag_expr_id, bk)
+    }
+
+    fn copy(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
+        (**self).copy(place_with_id, diag_expr_id)
+    }
+
+    fn mutate(&mut self, assignee_place: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
+        (**self).mutate(assignee_place, diag_expr_id)
+    }
+
+    fn bind(&mut self, binding_place: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
+        (**self).bind(binding_place, diag_expr_id)
+    }
+
+    fn fake_read(
+        &mut self,
+        place_with_id: &PlaceWithHirId<'tcx>,
+        cause: FakeReadCause,
+        diag_expr_id: HirId,
+    ) {
+        (**self).fake_read(place_with_id, cause, diag_expr_id)
+    }
+}
+
+pub trait TypeInformationCtxt<'tcx> {
+    type TypeckResults<'a>: Deref<Target = ty::TypeckResults<'tcx>>
+    where
+        Self: 'a;
+
+    type Error;
+
+    fn typeck_results(&self) -> Self::TypeckResults<'_>;
+
+    fn resolve_vars_if_possible<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T;
+
+    fn try_structurally_resolve_type(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx>;
+
+    fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error;
+
+    fn error_reported_in_ty(&self, ty: Ty<'tcx>) -> Result<(), Self::Error>;
+
+    fn tainted_by_errors(&self) -> Result<(), Self::Error>;
+
+    fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool;
+
+    fn body_owner_def_id(&self) -> LocalDefId;
+
+    fn tcx(&self) -> TyCtxt<'tcx>;
+}
+
+impl<'tcx> TypeInformationCtxt<'tcx> for &FnCtxt<'_, 'tcx> {
+    type TypeckResults<'a> = Ref<'a, ty::TypeckResults<'tcx>>
+    where
+        Self: 'a;
+
+    type Error = ErrorGuaranteed;
+
+    fn typeck_results(&self) -> Self::TypeckResults<'_> {
+        self.typeck_results.borrow()
+    }
+
+    fn resolve_vars_if_possible<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T {
+        self.infcx.resolve_vars_if_possible(t)
+    }
+
+    fn try_structurally_resolve_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+        (**self).try_structurally_resolve_type(sp, ty)
+    }
+
+    fn report_error(&self, span: Span, msg: impl ToString) -> Self::Error {
+        self.tcx.dcx().span_delayed_bug(span, msg.to_string())
+    }
+
+    fn error_reported_in_ty(&self, ty: Ty<'tcx>) -> Result<(), Self::Error> {
+        ty.error_reported()
+    }
+
+    fn tainted_by_errors(&self) -> Result<(), ErrorGuaranteed> {
+        if let Some(guar) = self.infcx.tainted_by_errors() { Err(guar) } else { Ok(()) }
+    }
+
+    fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
+        self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
+    }
+
+    fn body_owner_def_id(&self) -> LocalDefId {
+        self.body_id
+    }
+
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+}
+
+impl<'tcx> TypeInformationCtxt<'tcx> for (&LateContext<'tcx>, LocalDefId) {
+    type TypeckResults<'a> = &'tcx ty::TypeckResults<'tcx>
+    where
+        Self: 'a;
+
+    type Error = !;
+
+    fn typeck_results(&self) -> Self::TypeckResults<'_> {
+        self.0.maybe_typeck_results().expect("expected typeck results")
+    }
+
+    fn try_structurally_resolve_type(&self, _span: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
+        // FIXME: Maybe need to normalize here.
+        ty
+    }
+
+    fn resolve_vars_if_possible<T: TypeFoldable<TyCtxt<'tcx>>>(&self, t: T) -> T {
+        t
+    }
+
+    fn report_error(&self, span: Span, msg: impl ToString) -> ! {
+        span_bug!(span, "{}", msg.to_string())
+    }
+
+    fn error_reported_in_ty(&self, _ty: Ty<'tcx>) -> Result<(), !> {
+        Ok(())
+    }
+
+    fn tainted_by_errors(&self) -> Result<(), !> {
+        Ok(())
+    }
+
+    fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
+        ty.is_copy_modulo_regions(self.0.tcx, self.0.param_env)
+    }
+
+    fn body_owner_def_id(&self) -> LocalDefId {
+        self.1
+    }
+
+    fn tcx(&self) -> TyCtxt<'tcx> {
+        self.0.tcx
+    }
 }
 
 /// The ExprUseVisitor type
 ///
 /// This is the code that actually walks the tree.
-pub struct ExprUseVisitor<'a, 'tcx> {
-    mc: mc::MemCategorizationContext<'a, 'tcx>,
-    body_owner: LocalDefId,
-    delegate: &'a mut dyn Delegate<'tcx>,
+pub struct ExprUseVisitor<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> {
+    cx: Cx,
+    /// We use a `RefCell` here so that delegates can mutate themselves, but we can
+    /// still have calls to our own helper functions.
+    delegate: RefCell<D>,
+    upvars: Option<&'tcx FxIndexMap<HirId, hir::Upvar>>,
 }
 
-/// If the MC results in an error, it's because the type check
-/// failed (or will fail, when the error is uncovered and reported
-/// during writeback). In this case, we just ignore this part of the
-/// code.
-///
-/// Note that this macro appears similar to try!(), but, unlike try!(),
-/// it does not propagate the error.
-macro_rules! return_if_err {
-    ($inp: expr) => {
-        match $inp {
-            Ok(v) => v,
-            Err(()) => {
-                debug!("mc reported err");
-                return;
-            }
-        }
-    };
+impl<'a, 'tcx, D: Delegate<'tcx>> ExprUseVisitor<'tcx, (&'a LateContext<'tcx>, LocalDefId), D> {
+    pub fn for_clippy(cx: &'a LateContext<'tcx>, body_def_id: LocalDefId, delegate: D) -> Self {
+        Self::new((cx, body_def_id), delegate)
+    }
 }
 
-impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
+impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> {
     /// Creates the ExprUseVisitor, configuring it with the various options provided:
     ///
     /// - `delegate` -- who receives the callbacks
     /// - `param_env` --- parameter environment for trait lookups (esp. pertaining to `Copy`)
     /// - `typeck_results` --- typeck results for the code being analyzed
-    pub fn new(
-        delegate: &'a mut (dyn Delegate<'tcx> + 'a),
-        infcx: &'a InferCtxt<'tcx>,
-        body_owner: LocalDefId,
-        param_env: ty::ParamEnv<'tcx>,
-        typeck_results: &'a ty::TypeckResults<'tcx>,
-    ) -> Self {
+    pub(crate) fn new(cx: Cx, delegate: D) -> Self {
         ExprUseVisitor {
-            mc: mc::MemCategorizationContext::new(infcx, param_env, body_owner, typeck_results),
-            body_owner,
-            delegate,
+            delegate: RefCell::new(delegate),
+            upvars: cx.tcx().upvars_mentioned(cx.body_owner_def_id()),
+            cx,
         }
     }
 
-    #[instrument(skip(self), level = "debug")]
-    pub fn consume_body(&mut self, body: &hir::Body<'_>) {
+    pub fn consume_body(&self, body: &hir::Body<'_>) -> Result<(), Cx::Error> {
         for param in body.params {
-            let param_ty = return_if_err!(self.mc.pat_ty_adjusted(param.pat));
+            let param_ty = self.pat_ty_adjusted(param.pat)?;
             debug!("consume_body: param_ty = {:?}", param_ty);
 
-            let param_place = self.mc.cat_rvalue(param.hir_id, param_ty);
+            let param_place = self.cat_rvalue(param.hir_id, param_ty);
 
-            self.walk_irrefutable_pat(&param_place, param.pat);
+            self.walk_irrefutable_pat(&param_place, param.pat)?;
         }
 
-        self.consume_expr(body.value);
+        self.consume_expr(body.value)?;
+
+        Ok(())
     }
 
-    fn tcx(&self) -> TyCtxt<'tcx> {
-        self.mc.tcx()
+    fn consume_or_copy(&self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
+        debug!("delegate_consume(place_with_id={:?})", place_with_id);
+
+        if self.cx.type_is_copy_modulo_regions(place_with_id.place.ty()) {
+            self.delegate.borrow_mut().copy(place_with_id, diag_expr_id);
+        } else {
+            self.delegate.borrow_mut().consume(place_with_id, diag_expr_id);
+        }
     }
 
-    fn delegate_consume(&mut self, place_with_id: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) {
-        delegate_consume(&self.mc, self.delegate, place_with_id, diag_expr_id)
-    }
-
-    fn consume_exprs(&mut self, exprs: &[hir::Expr<'_>]) {
+    fn consume_exprs(&self, exprs: &[hir::Expr<'_>]) -> Result<(), Cx::Error> {
         for expr in exprs {
-            self.consume_expr(expr);
+            self.consume_expr(expr)?;
         }
+
+        Ok(())
     }
 
-    pub fn consume_expr(&mut self, expr: &hir::Expr<'_>) {
+    // FIXME: It's suspicious that this is public; clippy should probably use `walk_expr`.
+    pub fn consume_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
         debug!("consume_expr(expr={:?})", expr);
 
-        let place_with_id = return_if_err!(self.mc.cat_expr(expr));
-        self.delegate_consume(&place_with_id, place_with_id.hir_id);
-        self.walk_expr(expr);
+        let place_with_id = self.cat_expr(expr)?;
+        self.consume_or_copy(&place_with_id, place_with_id.hir_id);
+        self.walk_expr(expr)?;
+        Ok(())
     }
 
-    fn mutate_expr(&mut self, expr: &hir::Expr<'_>) {
-        let place_with_id = return_if_err!(self.mc.cat_expr(expr));
-        self.delegate.mutate(&place_with_id, place_with_id.hir_id);
-        self.walk_expr(expr);
+    fn mutate_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
+        let place_with_id = self.cat_expr(expr)?;
+        self.delegate.borrow_mut().mutate(&place_with_id, place_with_id.hir_id);
+        self.walk_expr(expr)?;
+        Ok(())
     }
 
-    fn borrow_expr(&mut self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) {
+    fn borrow_expr(&self, expr: &hir::Expr<'_>, bk: ty::BorrowKind) -> Result<(), Cx::Error> {
         debug!("borrow_expr(expr={:?}, bk={:?})", expr, bk);
 
-        let place_with_id = return_if_err!(self.mc.cat_expr(expr));
-        self.delegate.borrow(&place_with_id, place_with_id.hir_id, bk);
-
+        let place_with_id = self.cat_expr(expr)?;
+        self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk);
         self.walk_expr(expr)
     }
 
-    fn select_from_expr(&mut self, expr: &hir::Expr<'_>) {
-        self.walk_expr(expr)
-    }
-
-    pub fn walk_expr(&mut self, expr: &hir::Expr<'_>) {
+    pub fn walk_expr(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
         debug!("walk_expr(expr={:?})", expr);
 
-        self.walk_adjustment(expr);
+        self.walk_adjustment(expr)?;
 
         match expr.kind {
             hir::ExprKind::Path(_) => {}
 
-            hir::ExprKind::Type(subexpr, _) => self.walk_expr(subexpr),
+            hir::ExprKind::Type(subexpr, _) => {
+                self.walk_expr(subexpr)?;
+            }
 
             hir::ExprKind::Unary(hir::UnOp::Deref, base) => {
                 // *base
-                self.select_from_expr(base);
+                self.walk_expr(base)?;
             }
 
             hir::ExprKind::Field(base, _) => {
                 // base.f
-                self.select_from_expr(base);
+                self.walk_expr(base)?;
             }
 
             hir::ExprKind::Index(lhs, rhs, _) => {
                 // lhs[rhs]
-                self.select_from_expr(lhs);
-                self.consume_expr(rhs);
+                self.walk_expr(lhs)?;
+                self.consume_expr(rhs)?;
             }
 
             hir::ExprKind::Call(callee, args) => {
                 // callee(args)
-                self.consume_expr(callee);
-                self.consume_exprs(args);
+                self.consume_expr(callee)?;
+                self.consume_exprs(args)?;
             }
 
             hir::ExprKind::MethodCall(.., receiver, args, _) => {
                 // callee.m(args)
-                self.consume_expr(receiver);
-                self.consume_exprs(args);
+                self.consume_expr(receiver)?;
+                self.consume_exprs(args)?;
             }
 
             hir::ExprKind::Struct(_, fields, ref opt_with) => {
-                self.walk_struct_expr(fields, opt_with);
+                self.walk_struct_expr(fields, opt_with)?;
             }
 
             hir::ExprKind::Tup(exprs) => {
-                self.consume_exprs(exprs);
+                self.consume_exprs(exprs)?;
             }
 
             hir::ExprKind::If(cond_expr, then_expr, ref opt_else_expr) => {
-                self.consume_expr(cond_expr);
-                self.consume_expr(then_expr);
+                self.consume_expr(cond_expr)?;
+                self.consume_expr(then_expr)?;
                 if let Some(else_expr) = *opt_else_expr {
-                    self.consume_expr(else_expr);
+                    self.consume_expr(else_expr)?;
                 }
             }
 
             hir::ExprKind::Let(hir::LetExpr { pat, init, .. }) => {
-                self.walk_local(init, pat, None, |t| t.borrow_expr(init, ty::ImmBorrow))
+                self.walk_local(init, pat, None, || self.borrow_expr(init, ty::ImmBorrow))?;
             }
 
             hir::ExprKind::Match(discr, arms, _) => {
-                let discr_place = return_if_err!(self.mc.cat_expr(discr));
-                return_if_err!(self.maybe_read_scrutinee(
+                let discr_place = self.cat_expr(discr)?;
+                self.maybe_read_scrutinee(
                     discr,
                     discr_place.clone(),
                     arms.iter().map(|arm| arm.pat),
-                ));
+                )?;
 
                 // treatment of the discriminant is handled while walking the arms.
                 for arm in arms {
-                    self.walk_arm(&discr_place, arm);
+                    self.walk_arm(&discr_place, arm)?;
                 }
             }
 
             hir::ExprKind::Array(exprs) => {
-                self.consume_exprs(exprs);
+                self.consume_exprs(exprs)?;
             }
 
             hir::ExprKind::AddrOf(_, m, base) => {
@@ -272,21 +411,23 @@
                 // make sure that the thing we are pointing out stays valid
                 // for the lifetime `scope_r` of the resulting ptr:
                 let bk = ty::BorrowKind::from_mutbl(m);
-                self.borrow_expr(base, bk);
+                self.borrow_expr(base, bk)?;
             }
 
             hir::ExprKind::InlineAsm(asm) => {
                 for (op, _op_sp) in asm.operands {
                     match op {
-                        hir::InlineAsmOperand::In { expr, .. } => self.consume_expr(expr),
+                        hir::InlineAsmOperand::In { expr, .. } => {
+                            self.consume_expr(expr)?;
+                        }
                         hir::InlineAsmOperand::Out { expr: Some(expr), .. }
                         | hir::InlineAsmOperand::InOut { expr, .. } => {
-                            self.mutate_expr(expr);
+                            self.mutate_expr(expr)?;
                         }
                         hir::InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
-                            self.consume_expr(in_expr);
+                            self.consume_expr(in_expr)?;
                             if let Some(out_expr) = out_expr {
-                                self.mutate_expr(out_expr);
+                                self.mutate_expr(out_expr)?;
                             }
                         }
                         hir::InlineAsmOperand::Out { expr: None, .. }
@@ -294,7 +435,7 @@
                         | hir::InlineAsmOperand::SymFn { .. }
                         | hir::InlineAsmOperand::SymStatic { .. } => {}
                         hir::InlineAsmOperand::Label { block } => {
-                            self.walk_block(block);
+                            self.walk_block(block)?;
                         }
                     }
                 }
@@ -307,72 +448,74 @@
             | hir::ExprKind::Err(_) => {}
 
             hir::ExprKind::Loop(blk, ..) => {
-                self.walk_block(blk);
+                self.walk_block(blk)?;
             }
 
             hir::ExprKind::Unary(_, lhs) => {
-                self.consume_expr(lhs);
+                self.consume_expr(lhs)?;
             }
 
             hir::ExprKind::Binary(_, lhs, rhs) => {
-                self.consume_expr(lhs);
-                self.consume_expr(rhs);
+                self.consume_expr(lhs)?;
+                self.consume_expr(rhs)?;
             }
 
             hir::ExprKind::Block(blk, _) => {
-                self.walk_block(blk);
+                self.walk_block(blk)?;
             }
 
             hir::ExprKind::Break(_, ref opt_expr) | hir::ExprKind::Ret(ref opt_expr) => {
                 if let Some(expr) = *opt_expr {
-                    self.consume_expr(expr);
+                    self.consume_expr(expr)?;
                 }
             }
 
             hir::ExprKind::Become(call) => {
-                self.consume_expr(call);
+                self.consume_expr(call)?;
             }
 
             hir::ExprKind::Assign(lhs, rhs, _) => {
-                self.mutate_expr(lhs);
-                self.consume_expr(rhs);
+                self.mutate_expr(lhs)?;
+                self.consume_expr(rhs)?;
             }
 
             hir::ExprKind::Cast(base, _) => {
-                self.consume_expr(base);
+                self.consume_expr(base)?;
             }
 
             hir::ExprKind::DropTemps(expr) => {
-                self.consume_expr(expr);
+                self.consume_expr(expr)?;
             }
 
             hir::ExprKind::AssignOp(_, lhs, rhs) => {
-                if self.mc.typeck_results.is_method_call(expr) {
-                    self.consume_expr(lhs);
+                if self.cx.typeck_results().is_method_call(expr) {
+                    self.consume_expr(lhs)?;
                 } else {
-                    self.mutate_expr(lhs);
+                    self.mutate_expr(lhs)?;
                 }
-                self.consume_expr(rhs);
+                self.consume_expr(rhs)?;
             }
 
             hir::ExprKind::Repeat(base, _) => {
-                self.consume_expr(base);
+                self.consume_expr(base)?;
             }
 
             hir::ExprKind::Closure(closure) => {
-                self.walk_captures(closure);
+                self.walk_captures(closure)?;
             }
 
             hir::ExprKind::Yield(value, _) => {
-                self.consume_expr(value);
+                self.consume_expr(value)?;
             }
         }
+
+        Ok(())
     }
 
-    fn walk_stmt(&mut self, stmt: &hir::Stmt<'_>) {
+    fn walk_stmt(&self, stmt: &hir::Stmt<'_>) -> Result<(), Cx::Error> {
         match stmt.kind {
             hir::StmtKind::Let(hir::LetStmt { pat, init: Some(expr), els, .. }) => {
-                self.walk_local(expr, pat, *els, |_| {})
+                self.walk_local(expr, pat, *els, || Ok(()))?;
             }
 
             hir::StmtKind::Let(_) => {}
@@ -383,25 +526,26 @@
             }
 
             hir::StmtKind::Expr(expr) | hir::StmtKind::Semi(expr) => {
-                self.consume_expr(expr);
+                self.consume_expr(expr)?;
             }
         }
+
+        Ok(())
     }
 
     fn maybe_read_scrutinee<'t>(
-        &mut self,
+        &self,
         discr: &Expr<'_>,
         discr_place: PlaceWithHirId<'tcx>,
         pats: impl Iterator<Item = &'t hir::Pat<'t>>,
-    ) -> Result<(), ()> {
+    ) -> Result<(), Cx::Error> {
         // Matching should not always be considered a use of the place, hence
         // discr does not necessarily need to be borrowed.
         // We only want to borrow discr if the pattern contain something other
         // than wildcards.
-        let ExprUseVisitor { ref mc, body_owner: _, delegate: _ } = *self;
         let mut needs_to_be_read = false;
         for pat in pats {
-            mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
+            self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
                 match &pat.kind {
                     PatKind::Binding(.., opt_sub_pat) => {
                         // If the opt_sub_pat is None, then the binding does not count as
@@ -419,7 +563,7 @@
                         // A `Path` pattern is just a name like `Foo`. This is either a
                         // named constant or else it refers to an ADT variant
 
-                        let res = self.mc.typeck_results.qpath_res(qpath, pat.hir_id);
+                        let res = self.cx.typeck_results().qpath_res(qpath, pat.hir_id);
                         match res {
                             Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
                                 // Named constants have to be equated with the value
@@ -431,7 +575,8 @@
                             _ => {
                                 // Otherwise, this is a struct/enum variant, and so it's
                                 // only a read if we need to read the discriminant.
-                                needs_to_be_read |= is_multivariant_adt(place.place.ty());
+                                needs_to_be_read |=
+                                    self.is_multivariant_adt(place.place.ty(), pat.span);
                             }
                         }
                     }
@@ -443,7 +588,7 @@
                         // perform some reads).
 
                         let place_ty = place.place.ty();
-                        needs_to_be_read |= is_multivariant_adt(place_ty);
+                        needs_to_be_read |= self.is_multivariant_adt(place_ty, pat.span);
                     }
                     PatKind::Lit(_) | PatKind::Range(..) => {
                         // If the PatKind is a Lit or a Range then we want
@@ -473,18 +618,20 @@
                         // being examined
                     }
                 }
+
+                Ok(())
             })?
         }
 
         if needs_to_be_read {
-            self.borrow_expr(discr, ty::ImmBorrow);
+            self.borrow_expr(discr, ty::ImmBorrow)?;
         } else {
             let closure_def_id = match discr_place.place.base {
                 PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
                 _ => None,
             };
 
-            self.delegate.fake_read(
+            self.delegate.borrow_mut().fake_read(
                 &discr_place,
                 FakeReadCause::ForMatchedPlace(closure_def_id),
                 discr_place.hir_id,
@@ -492,90 +639,93 @@
 
             // We always want to walk the discriminant. We want to make sure, for instance,
             // that the discriminant has been initialized.
-            self.walk_expr(discr);
+            self.walk_expr(discr)?;
         }
         Ok(())
     }
 
     fn walk_local<F>(
-        &mut self,
+        &self,
         expr: &hir::Expr<'_>,
         pat: &hir::Pat<'_>,
         els: Option<&hir::Block<'_>>,
         mut f: F,
-    ) where
-        F: FnMut(&mut Self),
+    ) -> Result<(), Cx::Error>
+    where
+        F: FnMut() -> Result<(), Cx::Error>,
     {
-        self.walk_expr(expr);
-        let expr_place = return_if_err!(self.mc.cat_expr(expr));
-        f(self);
+        self.walk_expr(expr)?;
+        let expr_place = self.cat_expr(expr)?;
+        f()?;
         if let Some(els) = els {
             // borrowing because we need to test the discriminant
-            return_if_err!(self.maybe_read_scrutinee(
-                expr,
-                expr_place.clone(),
-                from_ref(pat).iter()
-            ));
-            self.walk_block(els)
+            self.maybe_read_scrutinee(expr, expr_place.clone(), from_ref(pat).iter())?;
+            self.walk_block(els)?;
         }
-        self.walk_irrefutable_pat(&expr_place, pat);
+        self.walk_irrefutable_pat(&expr_place, pat)?;
+        Ok(())
     }
 
     /// Indicates that the value of `blk` will be consumed, meaning either copied or moved
     /// depending on its type.
-    fn walk_block(&mut self, blk: &hir::Block<'_>) {
+    fn walk_block(&self, blk: &hir::Block<'_>) -> Result<(), Cx::Error> {
         debug!("walk_block(blk.hir_id={})", blk.hir_id);
 
         for stmt in blk.stmts {
-            self.walk_stmt(stmt);
+            self.walk_stmt(stmt)?;
         }
 
         if let Some(tail_expr) = blk.expr {
-            self.consume_expr(tail_expr);
+            self.consume_expr(tail_expr)?;
         }
+
+        Ok(())
     }
 
     fn walk_struct_expr<'hir>(
-        &mut self,
+        &self,
         fields: &[hir::ExprField<'_>],
         opt_with: &Option<&'hir hir::Expr<'_>>,
-    ) {
+    ) -> Result<(), Cx::Error> {
         // Consume the expressions supplying values for each field.
         for field in fields {
-            self.consume_expr(field.expr);
+            self.consume_expr(field.expr)?;
 
             // The struct path probably didn't resolve
-            if self.mc.typeck_results.opt_field_index(field.hir_id).is_none() {
-                self.tcx().dcx().span_delayed_bug(field.span, "couldn't resolve index for field");
+            if self.cx.typeck_results().opt_field_index(field.hir_id).is_none() {
+                self.cx
+                    .tcx()
+                    .dcx()
+                    .span_delayed_bug(field.span, "couldn't resolve index for field");
             }
         }
 
         let with_expr = match *opt_with {
             Some(w) => &*w,
             None => {
-                return;
+                return Ok(());
             }
         };
 
-        let with_place = return_if_err!(self.mc.cat_expr(with_expr));
+        let with_place = self.cat_expr(with_expr)?;
 
         // Select just those fields of the `with`
         // expression that will actually be used
-        match with_place.place.ty().kind() {
+        match self.cx.try_structurally_resolve_type(with_expr.span, with_place.place.ty()).kind() {
             ty::Adt(adt, args) if adt.is_struct() => {
                 // Consume those fields of the with expression that are needed.
                 for (f_index, with_field) in adt.non_enum_variant().fields.iter_enumerated() {
-                    let is_mentioned = fields
-                        .iter()
-                        .any(|f| self.mc.typeck_results.opt_field_index(f.hir_id) == Some(f_index));
+                    let is_mentioned = fields.iter().any(|f| {
+                        self.cx.typeck_results().opt_field_index(f.hir_id) == Some(f_index)
+                    });
                     if !is_mentioned {
-                        let field_place = self.mc.cat_projection(
-                            &*with_expr,
+                        let field_place = self.cat_projection(
+                            with_expr.hir_id,
                             with_place.clone(),
-                            with_field.ty(self.tcx(), args),
+                            with_field.ty(self.cx.tcx(), args),
                             ProjectionKind::Field(f_index, FIRST_VARIANT),
                         );
-                        self.delegate_consume(&field_place, field_place.hir_id);
+                        self.consume_or_copy(&field_place, field_place.hir_id);
                     }
                 }
             }
@@ -584,7 +734,7 @@
                 // struct; however, when EUV is run during typeck, it
                 // may not. This will generate an error earlier in typeck,
                 // so we can just ignore it.
-                if self.tcx().dcx().has_errors().is_none() {
+                if self.cx.tcx().dcx().has_errors().is_none() {
                     span_bug!(with_expr.span, "with expression doesn't evaluate to a struct");
                 }
             }
@@ -592,15 +742,18 @@
 
         // walk the with expression so that complex expressions
         // are properly handled.
-        self.walk_expr(with_expr);
+        self.walk_expr(with_expr)?;
+
+        Ok(())
     }
 
     /// Invoke the appropriate delegate calls for anything that gets
     /// consumed or borrowed as part of the automatic adjustment
     /// process.
-    fn walk_adjustment(&mut self, expr: &hir::Expr<'_>) {
-        let adjustments = self.mc.typeck_results.expr_adjustments(expr);
-        let mut place_with_id = return_if_err!(self.mc.cat_expr_unadjusted(expr));
+    fn walk_adjustment(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
+        let typeck_results = self.cx.typeck_results();
+        let adjustments = typeck_results.expr_adjustments(expr);
+        let mut place_with_id = self.cat_expr_unadjusted(expr)?;
         for adjustment in adjustments {
             debug!("walk_adjustment expr={:?} adj={:?}", expr, adjustment);
             match adjustment.kind {
@@ -609,7 +762,7 @@
                 | adjustment::Adjust::DynStar => {
                     // Creating a closure/fn-pointer or unsizing consumes
                     // the input and stores it into the resulting rvalue.
-                    self.delegate_consume(&place_with_id, place_with_id.hir_id);
+                    self.consume_or_copy(&place_with_id, place_with_id.hir_id);
                 }
 
                 adjustment::Adjust::Deref(None) => {}
@@ -621,23 +774,24 @@
                 // this is an autoref of `x`.
                 adjustment::Adjust::Deref(Some(ref deref)) => {
                     let bk = ty::BorrowKind::from_mutbl(deref.mutbl);
-                    self.delegate.borrow(&place_with_id, place_with_id.hir_id, bk);
+                    self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk);
                 }
 
                 adjustment::Adjust::Borrow(ref autoref) => {
                     self.walk_autoref(expr, &place_with_id, autoref);
                 }
             }
-            place_with_id =
-                return_if_err!(self.mc.cat_expr_adjusted(expr, place_with_id, adjustment));
+            place_with_id = self.cat_expr_adjusted(expr, place_with_id, adjustment)?;
         }
+
+        Ok(())
     }
 
     /// Walks the autoref `autoref` applied to the autoderef'd
     /// `expr`. `base_place` is the mem-categorized form of `expr`
     /// after all relevant autoderefs have occurred.
     fn walk_autoref(
-        &mut self,
+        &self,
         expr: &hir::Expr<'_>,
         base_place: &PlaceWithHirId<'tcx>,
         autoref: &adjustment::AutoBorrow<'tcx>,
@@ -649,7 +803,7 @@
 
         match *autoref {
             adjustment::AutoBorrow::Ref(_, m) => {
-                self.delegate.borrow(
+                self.delegate.borrow_mut().borrow(
                     base_place,
                     base_place.hir_id,
                     ty::BorrowKind::from_mutbl(m.into()),
@@ -659,80 +813,93 @@
             adjustment::AutoBorrow::RawPtr(m) => {
                 debug!("walk_autoref: expr.hir_id={} base_place={:?}", expr.hir_id, base_place);
 
-                self.delegate.borrow(base_place, base_place.hir_id, ty::BorrowKind::from_mutbl(m));
+                self.delegate.borrow_mut().borrow(
+                    base_place,
+                    base_place.hir_id,
+                    ty::BorrowKind::from_mutbl(m),
+                );
             }
         }
     }
 
-    fn walk_arm(&mut self, discr_place: &PlaceWithHirId<'tcx>, arm: &hir::Arm<'_>) {
+    fn walk_arm(
+        &self,
+        discr_place: &PlaceWithHirId<'tcx>,
+        arm: &hir::Arm<'_>,
+    ) -> Result<(), Cx::Error> {
         let closure_def_id = match discr_place.place.base {
             PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
             _ => None,
         };
 
-        self.delegate.fake_read(
+        self.delegate.borrow_mut().fake_read(
             discr_place,
             FakeReadCause::ForMatchedPlace(closure_def_id),
             discr_place.hir_id,
         );
-        self.walk_pat(discr_place, arm.pat, arm.guard.is_some());
+        self.walk_pat(discr_place, arm.pat, arm.guard.is_some())?;
 
         if let Some(ref e) = arm.guard {
-            self.consume_expr(e)
+            self.consume_expr(e)?;
         }
 
-        self.consume_expr(arm.body);
+        self.consume_expr(arm.body)?;
+        Ok(())
     }
 
     /// Walks a pat that occurs in isolation (i.e., top-level of fn argument or
     /// let binding, and *not* a match arm or nested pat.)
-    fn walk_irrefutable_pat(&mut self, discr_place: &PlaceWithHirId<'tcx>, pat: &hir::Pat<'_>) {
+    fn walk_irrefutable_pat(
+        &self,
+        discr_place: &PlaceWithHirId<'tcx>,
+        pat: &hir::Pat<'_>,
+    ) -> Result<(), Cx::Error> {
         let closure_def_id = match discr_place.place.base {
             PlaceBase::Upvar(upvar_id) => Some(upvar_id.closure_expr_id),
             _ => None,
         };
 
-        self.delegate.fake_read(
+        self.delegate.borrow_mut().fake_read(
             discr_place,
             FakeReadCause::ForLet(closure_def_id),
             discr_place.hir_id,
         );
-        self.walk_pat(discr_place, pat, false);
+        self.walk_pat(discr_place, pat, false)?;
+        Ok(())
     }
 
     /// The core driver for walking a pattern
     fn walk_pat(
-        &mut self,
+        &self,
         discr_place: &PlaceWithHirId<'tcx>,
         pat: &hir::Pat<'_>,
         has_guard: bool,
-    ) {
+    ) -> Result<(), Cx::Error> {
         debug!("walk_pat(discr_place={:?}, pat={:?}, has_guard={:?})", discr_place, pat, has_guard);
 
-        let tcx = self.tcx();
-        let ExprUseVisitor { ref mc, body_owner: _, ref mut delegate } = *self;
-        return_if_err!(mc.cat_pattern(discr_place.clone(), pat, |place, pat| {
+        let tcx = self.cx.tcx();
+        self.cat_pattern(discr_place.clone(), pat, &mut |place, pat| {
             if let PatKind::Binding(_, canonical_id, ..) = pat.kind {
                 debug!("walk_pat: binding place={:?} pat={:?}", place, pat);
                 if let Some(bm) =
-                    mc.typeck_results.extract_binding_mode(tcx.sess, pat.hir_id, pat.span)
+                    self.cx.typeck_results().extract_binding_mode(tcx.sess, pat.hir_id, pat.span)
                 {
                     debug!("walk_pat: pat.hir_id={:?} bm={:?}", pat.hir_id, bm);
 
                     // pat_ty: the type of the binding being produced.
-                    let pat_ty = return_if_err!(mc.node_ty(pat.hir_id));
+                    let pat_ty = self.node_ty(pat.hir_id)?;
                     debug!("walk_pat: pat_ty={:?}", pat_ty);
 
                     let def = Res::Local(canonical_id);
-                    if let Ok(ref binding_place) = mc.cat_res(pat.hir_id, pat.span, pat_ty, def) {
-                        delegate.bind(binding_place, binding_place.hir_id);
+                    if let Ok(ref binding_place) = self.cat_res(pat.hir_id, pat.span, pat_ty, def) {
+                        self.delegate.borrow_mut().bind(binding_place, binding_place.hir_id);
                     }
 
                     // Subtle: MIR desugaring introduces immutable borrows for each pattern
                     // binding when lowering pattern guards to ensure that the guard does not
                     // modify the scrutinee.
                     if has_guard {
-                        delegate.borrow(place, discr_place.hir_id, ImmBorrow);
+                        self.delegate.borrow_mut().borrow(place, discr_place.hir_id, ImmBorrow);
                     }
 
                     // It is also a borrow or copy/move of the value being matched.
@@ -742,11 +909,11 @@
                     match bm.0 {
                         hir::ByRef::Yes(m) => {
                             let bk = ty::BorrowKind::from_mutbl(m);
-                            delegate.borrow(place, discr_place.hir_id, bk);
+                            self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
                         }
                         hir::ByRef::No => {
                             debug!("walk_pat binding consuming pat");
-                            delegate_consume(mc, *delegate, place, discr_place.hir_id);
+                            self.consume_or_copy(place, discr_place.hir_id);
                         }
                     }
                 }
@@ -755,12 +922,14 @@
                 // determines whether to borrow *at the level of the deref pattern* rather than
                 // borrowing the bound place (since that inner place is inside the temporary that
                 // stores the result of calling `deref()`/`deref_mut()` so can't be captured).
-                let mutable = mc.typeck_results.pat_has_ref_mut_binding(subpattern);
+                let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpattern);
                 let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
                 let bk = ty::BorrowKind::from_mutbl(mutability);
-                delegate.borrow(place, discr_place.hir_id, bk);
+                self.delegate.borrow_mut().borrow(place, discr_place.hir_id, bk);
             }
-        }));
+
+            Ok(())
+        })
     }
 
     /// Handle the case where the current body contains a closure.
@@ -782,7 +951,7 @@
     ///
     /// - When reporting the Place back to the Delegate, ensure that the UpvarId uses the enclosing
     /// closure as the DefId.
-    fn walk_captures(&mut self, closure_expr: &hir::Closure<'_>) {
+    fn walk_captures(&self, closure_expr: &hir::Closure<'_>) -> Result<(), Cx::Error> {
         fn upvar_is_local_variable(
             upvars: Option<&FxIndexMap<HirId, hir::Upvar>>,
             upvar_id: HirId,
@@ -793,21 +962,21 @@
 
         debug!("walk_captures({:?})", closure_expr);
 
-        let tcx = self.tcx();
+        let tcx = self.cx.tcx();
         let closure_def_id = closure_expr.def_id;
-        let upvars = tcx.upvars_mentioned(self.body_owner);
-
         // For purposes of this function, coroutine and closures are equivalent.
-        let body_owner_is_closure =
-            matches!(tcx.hir().body_owner_kind(self.body_owner), hir::BodyOwnerKind::Closure,);
+        let body_owner_is_closure = matches!(
+            tcx.hir().body_owner_kind(self.cx.body_owner_def_id()),
+            hir::BodyOwnerKind::Closure
+        );
 
         // If we have a nested closure, we want to include the fake reads present in the nested closure.
-        if let Some(fake_reads) = self.mc.typeck_results.closure_fake_reads.get(&closure_def_id) {
+        if let Some(fake_reads) = self.cx.typeck_results().closure_fake_reads.get(&closure_def_id) {
             for (fake_read, cause, hir_id) in fake_reads.iter() {
                 match fake_read.base {
                     PlaceBase::Upvar(upvar_id) => {
                         if upvar_is_local_variable(
-                            upvars,
+                            self.upvars,
                             upvar_id.var_path.hir_id,
                             body_owner_is_closure,
                         ) {
@@ -837,7 +1006,7 @@
                         );
                     }
                 };
-                self.delegate.fake_read(
+                self.delegate.borrow_mut().fake_read(
                     &PlaceWithHirId { place: fake_read.clone(), hir_id: *hir_id },
                     *cause,
                     *hir_id,
@@ -845,10 +1014,14 @@
             }
         }
 
-        if let Some(min_captures) = self.mc.typeck_results.closure_min_captures.get(&closure_def_id)
+        if let Some(min_captures) =
+            self.cx.typeck_results().closure_min_captures.get(&closure_def_id)
         {
             for (var_hir_id, min_list) in min_captures.iter() {
-                if upvars.map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id)) {
+                if self
+                    .upvars
+                    .map_or(body_owner_is_closure, |upvars| !upvars.contains_key(var_hir_id))
+                {
                     // The nested closure might be capturing the current (enclosing) closure's local variables.
                     // We check if the root variable is ever mentioned within the enclosing closure, if not
                     // then for the current body (if it's a closure) these aren't captures, we will ignore them.
@@ -860,7 +1033,7 @@
 
                     let place_base = if body_owner_is_closure {
                         // Mark the place to be captured by the enclosing closure
-                        PlaceBase::Upvar(ty::UpvarId::new(*var_hir_id, self.body_owner))
+                        PlaceBase::Upvar(ty::UpvarId::new(*var_hir_id, self.cx.body_owner_def_id()))
                     } else {
                         // If the body owner isn't a closure then the variable must
                         // be a local variable
@@ -878,10 +1051,10 @@
 
                     match capture_info.capture_kind {
                         ty::UpvarCapture::ByValue => {
-                            self.delegate_consume(&place_with_id, place_with_id.hir_id);
+                            self.consume_or_copy(&place_with_id, place_with_id.hir_id);
                         }
                         ty::UpvarCapture::ByRef(upvar_borrow) => {
-                            self.delegate.borrow(
+                            self.delegate.borrow_mut().borrow(
                                 &place_with_id,
                                 place_with_id.hir_id,
                                 upvar_borrow,
@@ -891,53 +1064,743 @@
                 }
             }
         }
+
+        Ok(())
     }
 }
 
-fn copy_or_move<'a, 'tcx>(
-    mc: &mc::MemCategorizationContext<'a, 'tcx>,
-    place_with_id: &PlaceWithHirId<'tcx>,
-) -> ConsumeMode {
-    if !mc.type_is_copy_modulo_regions(place_with_id.place.ty()) {
-        ConsumeMode::Move
-    } else {
-        ConsumeMode::Copy
-    }
-}
-
-// - If a place is used in a `ByValue` context then move it if it's not a `Copy` type.
-// - If the place that is a `Copy` type consider it an `ImmBorrow`.
-fn delegate_consume<'a, 'tcx>(
-    mc: &mc::MemCategorizationContext<'a, 'tcx>,
-    delegate: &mut (dyn Delegate<'tcx> + 'a),
-    place_with_id: &PlaceWithHirId<'tcx>,
-    diag_expr_id: HirId,
-) {
-    debug!("delegate_consume(place_with_id={:?})", place_with_id);
-
-    let mode = copy_or_move(mc, place_with_id);
-
-    match mode {
-        ConsumeMode::Move => delegate.consume(place_with_id, diag_expr_id),
-        ConsumeMode::Copy => delegate.copy(place_with_id, diag_expr_id),
-    }
-}
-
-fn is_multivariant_adt(ty: Ty<'_>) -> bool {
-    if let ty::Adt(def, _) = ty.kind() {
-        // Note that if a non-exhaustive SingleVariant is defined in another crate, we need
-        // to assume that more cases will be added to the variant in the future. This mean
-        // that we should handle non-exhaustive SingleVariant the same way we would handle
-        // a MultiVariant.
-        // If the variant is not local it must be defined in another crate.
-        let is_non_exhaustive = match def.adt_kind() {
-            AdtKind::Struct | AdtKind::Union => {
-                def.non_enum_variant().is_field_list_non_exhaustive()
+/// The job of the categorization methods is to analyze an expression to
+/// determine what kind of memory is used in evaluating it (for example,
+/// where dereferences occur and what kind of pointer is dereferenced;
+/// whether the memory is mutable, etc.).
+///
+/// Categorization effectively transforms all of our expressions into
+/// expressions of the following forms (the actual enum has many more
+/// possibilities, naturally, but they are all variants of these base
+/// forms):
+/// ```ignore (not-rust)
+/// E = rvalue    // some computed rvalue
+///   | x         // address of a local variable or argument
+///   | *E        // deref of a ptr
+///   | E.comp    // access to an interior component
+/// ```
+/// Imagine a routine ToAddr(Expr) that evaluates an expression and returns an
+/// address where the result is to be found. If Expr is a place, then this
+/// is the address of the place. If `Expr` is an rvalue, this is the address of
+/// some temporary spot in memory where the result is stored.
+///
+/// Now, `cat_expr()` classifies the expression `Expr` and the address `A = ToAddr(Expr)`
+/// as follows:
+///
+/// - `cat`: what kind of expression was this? This is a subset of the
+///   full expression forms which only includes those that we care about
+///   for the purpose of the analysis.
+/// - `mutbl`: mutability of the address `A`.
+/// - `ty`: the type of data found at the address `A`.
+///
+/// The resulting categorization tree differs somewhat from the expressions
+/// themselves. For example, auto-derefs are explicit. Also, an index `a[b]` is
+/// decomposed into two operations: a dereference to reach the array data and
+/// then an index to jump forward to the relevant item.
+///
+/// ## By-reference upvars
+///
+/// One part of the codegen which may be non-obvious is that we translate
+/// closure upvars into the dereference of a borrowed pointer; this more closely
+/// resembles the runtime codegen. So, for example, if we had:
+///
+///     let mut x = 3;
+///     let y = 5;
+///     let inc = || x += y;
+///
+/// Then when we categorize `x` (*within* the closure) we would yield a
+/// result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference
+/// tied to `x`. The type of `x'` will be a borrowed pointer.
+impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx, Cx, D> {
+    fn resolve_type_vars_or_error(
+        &self,
+        id: HirId,
+        ty: Option<Ty<'tcx>>,
+    ) -> Result<Ty<'tcx>, Cx::Error> {
+        match ty {
+            Some(ty) => {
+                let ty = self.cx.resolve_vars_if_possible(ty);
+                self.cx.error_reported_in_ty(ty)?;
+                if ty.is_ty_var() {
+                    debug!("resolve_type_vars_or_error: infer var from {:?}", ty);
+                    Err(self
+                        .cx
+                        .report_error(self.cx.tcx().hir().span(id), "encountered type variable"))
+                } else {
+                    Ok(ty)
+                }
             }
-            AdtKind::Enum => def.is_variant_list_non_exhaustive(),
+            None => {
+                // FIXME: We shouldn't be relying on the infcx being tainted.
+                self.cx.tainted_by_errors()?;
+                bug!(
+                    "no type for node {} in mem_categorization",
+                    self.cx.tcx().hir().node_to_string(id)
+                );
+            }
+        }
+    }
+
+    fn node_ty(&self, hir_id: HirId) -> Result<Ty<'tcx>, Cx::Error> {
+        self.resolve_type_vars_or_error(hir_id, self.cx.typeck_results().node_type_opt(hir_id))
+    }
+
+    fn expr_ty(&self, expr: &hir::Expr<'_>) -> Result<Ty<'tcx>, Cx::Error> {
+        self.resolve_type_vars_or_error(expr.hir_id, self.cx.typeck_results().expr_ty_opt(expr))
+    }
+
+    fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> Result<Ty<'tcx>, Cx::Error> {
+        self.resolve_type_vars_or_error(
+            expr.hir_id,
+            self.cx.typeck_results().expr_ty_adjusted_opt(expr),
+        )
+    }
+
+    /// Returns the type of value that this pattern matches against.
+    /// Some non-obvious cases:
+    ///
+    /// - a `ref x` binding matches against a value of type `T` and gives
+    ///   `x` the type `&T`; we return `T`.
+    /// - a pattern with implicit derefs (thanks to default binding
+    ///   modes #42640) may look like `Some(x)` but in fact have
+    ///   implicit deref patterns attached (e.g., it is really
+    ///   `&Some(x)`). In that case, we return the "outermost" type
+    ///   (e.g., `&Option<T>`).
+    fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> Result<Ty<'tcx>, Cx::Error> {
+        // Check for implicit `&` types wrapping the pattern; note
+        // that these are never attached to binding patterns, so
+        // actually this is somewhat "disjoint" from the code below
+        // that aims to account for `ref x`.
+        if let Some(vec) = self.cx.typeck_results().pat_adjustments().get(pat.hir_id) {
+            if let Some(first_ty) = vec.first() {
+                debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
+                return Ok(*first_ty);
+            }
+        } else if let PatKind::Ref(subpat, _) = pat.kind
+            && self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id)
+        {
+            return self.pat_ty_adjusted(subpat);
+        }
+
+        self.pat_ty_unadjusted(pat)
+    }
+
+    /// Like `TypeckResults::pat_ty`, but ignores implicit `&` patterns.
+    fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> Result<Ty<'tcx>, Cx::Error> {
+        let base_ty = self.node_ty(pat.hir_id)?;
+        trace!(?base_ty);
+
+        // This code detects whether we are looking at a `ref x`,
+        // and if so, figures out what the type *being borrowed* is.
+        match pat.kind {
+            PatKind::Binding(..) => {
+                let bm = *self
+                    .cx
+                    .typeck_results()
+                    .pat_binding_modes()
+                    .get(pat.hir_id)
+                    .expect("missing binding mode");
+
+                if matches!(bm.0, hir::ByRef::Yes(_)) {
+                    // a bind-by-ref means that the base_ty will be the type of the ident itself,
+                    // but what we want here is the type of the underlying value being borrowed.
+                    // So peel off one-level, turning the &T into T.
+                    match self
+                        .cx
+                        .try_structurally_resolve_type(pat.span, base_ty)
+                        .builtin_deref(false)
+                    {
+                        Some(ty) => Ok(ty),
+                        None => {
+                            debug!("By-ref binding of non-derefable type");
+                            Err(self
+                                .cx
+                                .report_error(pat.span, "by-ref binding of non-derefable type"))
+                        }
+                    }
+                } else {
+                    Ok(base_ty)
+                }
+            }
+            _ => Ok(base_ty),
+        }
+    }
+
+    fn cat_expr(&self, expr: &hir::Expr<'_>) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
+        self.cat_expr_(expr, self.cx.typeck_results().expr_adjustments(expr))
+    }
+
+    /// This recursion helper avoids going through *too many*
+    /// adjustments, since *only* non-overloaded deref recurses.
+    fn cat_expr_(
+        &self,
+        expr: &hir::Expr<'_>,
+        adjustments: &[adjustment::Adjustment<'tcx>],
+    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
+        match adjustments.split_last() {
+            None => self.cat_expr_unadjusted(expr),
+            Some((adjustment, previous)) => {
+                self.cat_expr_adjusted_with(expr, || self.cat_expr_(expr, previous), adjustment)
+            }
+        }
+    }
+
+    fn cat_expr_adjusted(
+        &self,
+        expr: &hir::Expr<'_>,
+        previous: PlaceWithHirId<'tcx>,
+        adjustment: &adjustment::Adjustment<'tcx>,
+    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
+        self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
+    }
+
+    fn cat_expr_adjusted_with<F>(
+        &self,
+        expr: &hir::Expr<'_>,
+        previous: F,
+        adjustment: &adjustment::Adjustment<'tcx>,
+    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error>
+    where
+        F: FnOnce() -> Result<PlaceWithHirId<'tcx>, Cx::Error>,
+    {
+        let target = self.cx.resolve_vars_if_possible(adjustment.target);
+        match adjustment.kind {
+            adjustment::Adjust::Deref(overloaded) => {
+                // Equivalent to *expr or something similar.
+                let base = if let Some(deref) = overloaded {
+                    let ref_ty = Ty::new_ref(self.cx.tcx(), deref.region, target, deref.mutbl);
+                    self.cat_rvalue(expr.hir_id, ref_ty)
+                } else {
+                    previous()?
+                };
+                self.cat_deref(expr.hir_id, base)
+            }
+
+            adjustment::Adjust::NeverToAny
+            | adjustment::Adjust::Pointer(_)
+            | adjustment::Adjust::Borrow(_)
+            | adjustment::Adjust::DynStar => {
+                // Result is an rvalue.
+                Ok(self.cat_rvalue(expr.hir_id, target))
+            }
+        }
+    }
+
+    fn cat_expr_unadjusted(&self, expr: &hir::Expr<'_>) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
+        let expr_ty = self.expr_ty(expr)?;
+        match expr.kind {
+            hir::ExprKind::Unary(hir::UnOp::Deref, e_base) => {
+                if self.cx.typeck_results().is_method_call(expr) {
+                    self.cat_overloaded_place(expr, e_base)
+                } else {
+                    let base = self.cat_expr(e_base)?;
+                    self.cat_deref(expr.hir_id, base)
+                }
+            }
+
+            hir::ExprKind::Field(base, _) => {
+                let base = self.cat_expr(base)?;
+                debug!(?base);
+
+                let field_idx = self
+                    .cx
+                    .typeck_results()
+                    .field_indices()
+                    .get(expr.hir_id)
+                    .cloned()
+                    .expect("Field index not found");
+
+                Ok(self.cat_projection(
+                    expr.hir_id,
+                    base,
+                    expr_ty,
+                    ProjectionKind::Field(field_idx, FIRST_VARIANT),
+                ))
+            }
+
+            hir::ExprKind::Index(base, _, _) => {
+                if self.cx.typeck_results().is_method_call(expr) {
+                    // If this is an index implemented by a method call, then it
+                    // will include an implicit deref of the result.
+                    // The call to index() returns a `&T` value, which
+                    // is an rvalue. That is what we will be
+                    // dereferencing.
+                    self.cat_overloaded_place(expr, base)
+                } else {
+                    let base = self.cat_expr(base)?;
+                    Ok(self.cat_projection(expr.hir_id, base, expr_ty, ProjectionKind::Index))
+                }
+            }
+
+            hir::ExprKind::Path(ref qpath) => {
+                let res = self.cx.typeck_results().qpath_res(qpath, expr.hir_id);
+                self.cat_res(expr.hir_id, expr.span, expr_ty, res)
+            }
+
+            hir::ExprKind::Type(e, _) => self.cat_expr(e),
+
+            hir::ExprKind::AddrOf(..)
+            | hir::ExprKind::Call(..)
+            | hir::ExprKind::Assign(..)
+            | hir::ExprKind::AssignOp(..)
+            | hir::ExprKind::Closure { .. }
+            | hir::ExprKind::Ret(..)
+            | hir::ExprKind::Become(..)
+            | hir::ExprKind::Unary(..)
+            | hir::ExprKind::Yield(..)
+            | hir::ExprKind::MethodCall(..)
+            | hir::ExprKind::Cast(..)
+            | hir::ExprKind::DropTemps(..)
+            | hir::ExprKind::Array(..)
+            | hir::ExprKind::If(..)
+            | hir::ExprKind::Tup(..)
+            | hir::ExprKind::Binary(..)
+            | hir::ExprKind::Block(..)
+            | hir::ExprKind::Let(..)
+            | hir::ExprKind::Loop(..)
+            | hir::ExprKind::Match(..)
+            | hir::ExprKind::Lit(..)
+            | hir::ExprKind::ConstBlock(..)
+            | hir::ExprKind::Break(..)
+            | hir::ExprKind::Continue(..)
+            | hir::ExprKind::Struct(..)
+            | hir::ExprKind::Repeat(..)
+            | hir::ExprKind::InlineAsm(..)
+            | hir::ExprKind::OffsetOf(..)
+            | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr_ty)),
+        }
+    }
+
+    fn cat_res(
+        &self,
+        hir_id: HirId,
+        span: Span,
+        expr_ty: Ty<'tcx>,
+        res: Res,
+    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
+        match res {
+            Res::Def(
+                DefKind::Ctor(..)
+                | DefKind::Const
+                | DefKind::ConstParam
+                | DefKind::AssocConst
+                | DefKind::Fn
+                | DefKind::AssocFn,
+                _,
+            )
+            | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, expr_ty)),
+
+            Res::Def(DefKind::Static { .. }, _) => {
+                Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new()))
+            }
+
+            Res::Local(var_id) => {
+                if self.upvars.is_some_and(|upvars| upvars.contains_key(&var_id)) {
+                    self.cat_upvar(hir_id, var_id)
+                } else {
+                    Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Local(var_id), Vec::new()))
+                }
+            }
+
+            def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def),
+        }
+    }
+
+    /// Categorize an upvar.
+    ///
+    /// Note: the actual upvar access contains invisible derefs of closure
+    /// environment and upvar reference as appropriate. Only regionck cares
+    /// about these dereferences, so we let it compute them as needed.
+    fn cat_upvar(&self, hir_id: HirId, var_id: HirId) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
+        let closure_expr_def_id = self.cx.body_owner_def_id();
+
+        let upvar_id = ty::UpvarId {
+            var_path: ty::UpvarPath { hir_id: var_id },
+            closure_expr_id: closure_expr_def_id,
         };
-        def.variants().len() > 1 || (!def.did().is_local() && is_non_exhaustive)
-    } else {
-        false
+        let var_ty = self.node_ty(var_id)?;
+
+        Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new()))
+    }
+
+    fn cat_rvalue(&self, hir_id: HirId, expr_ty: Ty<'tcx>) -> PlaceWithHirId<'tcx> {
+        PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new())
+    }
+
+    fn cat_projection(
+        &self,
+        node: HirId,
+        base_place: PlaceWithHirId<'tcx>,
+        ty: Ty<'tcx>,
+        kind: ProjectionKind,
+    ) -> PlaceWithHirId<'tcx> {
+        let place_ty = base_place.place.ty();
+        let mut projections = base_place.place.projections;
+
+        let node_ty = self.cx.typeck_results().node_type(node);
+        // Opaque types can't have field projections, but we can instead convert
+        // the current place in-place (heh) to the hidden type, and then apply all
+        // follow up projections on that.
+        if node_ty != place_ty
+            && self
+                .cx
+                .try_structurally_resolve_type(
+                    self.cx.tcx().hir().span(base_place.hir_id),
+                    place_ty,
+                )
+                .is_impl_trait()
+        {
+            projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
+        }
+        projections.push(Projection { kind, ty });
+        PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections)
+    }
+
+    fn cat_overloaded_place(
+        &self,
+        expr: &hir::Expr<'_>,
+        base: &hir::Expr<'_>,
+    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
+        // Reconstruct the output assuming it's a reference with the
+        // same region and mutability as the receiver. This holds for
+        // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
+        let place_ty = self.expr_ty(expr)?;
+        let base_ty = self.expr_ty_adjusted(base)?;
+
+        let ty::Ref(region, _, mutbl) =
+            *self.cx.try_structurally_resolve_type(base.span, base_ty).kind()
+        else {
+            span_bug!(expr.span, "cat_overloaded_place: base is not a reference");
+        };
+        let ref_ty = Ty::new_ref(self.cx.tcx(), region, place_ty, mutbl);
+
+        let base = self.cat_rvalue(expr.hir_id, ref_ty);
+        self.cat_deref(expr.hir_id, base)
+    }
+
+    fn cat_deref(
+        &self,
+        node: HirId,
+        base_place: PlaceWithHirId<'tcx>,
+    ) -> Result<PlaceWithHirId<'tcx>, Cx::Error> {
+        let base_curr_ty = base_place.place.ty();
+        let deref_ty = match self
+            .cx
+            .try_structurally_resolve_type(
+                self.cx.tcx().hir().span(base_place.hir_id),
+                base_curr_ty,
+            )
+            .builtin_deref(true)
+        {
+            Some(ty) => ty,
+            None => {
+                debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
+                return Err(self.cx.report_error(
+                    self.cx.tcx().hir().span(node),
+                    "explicit deref of non-derefable type",
+                ));
+            }
+        };
+        let mut projections = base_place.place.projections;
+        projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty });
+
+        Ok(PlaceWithHirId::new(node, base_place.place.base_ty, base_place.place.base, projections))
+    }
+
+    /// Returns the variant index for an ADT used within a Struct or TupleStruct pattern
+    /// Here `pat_hir_id` is the HirId of the pattern itself.
+    fn variant_index_for_adt(
+        &self,
+        qpath: &hir::QPath<'_>,
+        pat_hir_id: HirId,
+        span: Span,
+    ) -> Result<VariantIdx, Cx::Error> {
+        let res = self.cx.typeck_results().qpath_res(qpath, pat_hir_id);
+        let ty = self.cx.typeck_results().node_type(pat_hir_id);
+        let ty::Adt(adt_def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() else {
+            return Err(self
+                .cx
+                .report_error(span, "struct or tuple struct pattern not applied to an ADT"));
+        };
+
+        match res {
+            Res::Def(DefKind::Variant, variant_id) => Ok(adt_def.variant_index_with_id(variant_id)),
+            Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
+                Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id))
+            }
+            Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
+            | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
+            | Res::SelfCtor(..)
+            | Res::SelfTyParam { .. }
+            | Res::SelfTyAlias { .. } => {
+                // Structs and Unions have only have one variant.
+                Ok(FIRST_VARIANT)
+            }
+            _ => bug!("expected ADT path, found={:?}", res),
+        }
+    }
+
+    /// Returns the total number of fields in an ADT variant used within a pattern.
+    /// Here `pat_hir_id` is the HirId of the pattern itself.
+    fn total_fields_in_adt_variant(
+        &self,
+        pat_hir_id: HirId,
+        variant_index: VariantIdx,
+        span: Span,
+    ) -> Result<usize, Cx::Error> {
+        let ty = self.cx.typeck_results().node_type(pat_hir_id);
+        match self.cx.try_structurally_resolve_type(span, ty).kind() {
+            ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()),
+            _ => {
+                self.cx
+                    .tcx()
+                    .dcx()
+                    .span_bug(span, "struct or tuple struct pattern not applied to an ADT");
+            }
+        }
+    }
+
+    /// Returns the total number of fields in a tuple used within a Tuple pattern.
+    /// Here `pat_hir_id` is the HirId of the pattern itself.
+    fn total_fields_in_tuple(&self, pat_hir_id: HirId, span: Span) -> Result<usize, Cx::Error> {
+        let ty = self.cx.typeck_results().node_type(pat_hir_id);
+        match self.cx.try_structurally_resolve_type(span, ty).kind() {
+            ty::Tuple(args) => Ok(args.len()),
+            _ => Err(self.cx.report_error(span, "tuple pattern not applied to a tuple")),
+        }
+    }
+
+    /// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
+    /// is being matched against.
+    ///
+    /// In general, the way that this works is that we walk down the pattern,
+    /// constructing a `PlaceWithHirId` that represents the path that will be taken
+    /// to reach the value being matched.
+    fn cat_pattern<F>(
+        &self,
+        mut place_with_id: PlaceWithHirId<'tcx>,
+        pat: &hir::Pat<'_>,
+        op: &mut F,
+    ) -> Result<(), Cx::Error>
+    where
+        F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>) -> Result<(), Cx::Error>,
+    {
+        // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly.
+        // `PlaceWithHirId`s are constructed differently from patterns. For example, in
+        //
+        // ```
+        // match foo {
+        //     &&Some(x, ) => { ... },
+        //     _ => { ... },
+        // }
+        // ```
+        //
+        // the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the
+        // corresponding `PlaceWithHirId` we start with the `PlaceWithHirId` for `foo`, and then, by traversing the
+        // pattern, try to answer the question: given the address of `foo`, how is `x` reached?
+        //
+        // `&&Some(x,)` `place_foo`
+        //  `&Some(x,)` `deref { place_foo}`
+        //   `Some(x,)` `deref { deref { place_foo }}`
+        //       `(x,)` `field0 { deref { deref { place_foo }}}` <- resulting place
+        //
+        // The above example has no adjustments. If the code were instead the (after adjustments,
+        // equivalent) version
+        //
+        // ```
+        // match foo {
+        //     Some(x, ) => { ... },
+        //     _ => { ... },
+        // }
+        // ```
+        //
+        // Then we see that to get the same result, we must start with
+        // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
+        // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
+        for _ in
+            0..self.cx.typeck_results().pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len())
+        {
+            debug!("applying adjustment to place_with_id={:?}", place_with_id);
+            place_with_id = self.cat_deref(pat.hir_id, place_with_id)?;
+        }
+        let place_with_id = place_with_id; // lose mutability
+        debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id);
+
+        // Invoke the callback, but only now, after the `place_with_id` has adjusted.
+        //
+        // To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that
+        // case, the initial `place_with_id` will be that for `&Some(3)` and the pattern is `Some(x)`. We
+        // don't want to call `op` with these incompatible values. As written, what happens instead
+        // is that `op` is called with the adjusted place (that for `*&Some(3)`) and the pattern
+        // `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)`
+        // result in the place `Downcast<Some>(*&Some(3)).0` associated to `x` and invoke `op` with
+        // that (where the `ref` on `x` is implied).
+        op(&place_with_id, pat)?;
+
+        match pat.kind {
+            PatKind::Tuple(subpats, dots_pos) => {
+                // (p1, ..., pN)
+                let total_fields = self.total_fields_in_tuple(pat.hir_id, pat.span)?;
+
+                for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
+                    let subpat_ty = self.pat_ty_adjusted(subpat)?;
+                    let projection_kind =
+                        ProjectionKind::Field(FieldIdx::from_usize(i), FIRST_VARIANT);
+                    let sub_place = self.cat_projection(
+                        pat.hir_id,
+                        place_with_id.clone(),
+                        subpat_ty,
+                        projection_kind,
+                    );
+                    self.cat_pattern(sub_place, subpat, op)?;
+                }
+            }
+
+            PatKind::TupleStruct(ref qpath, subpats, dots_pos) => {
+                // S(p1, ..., pN)
+                let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
+                let total_fields =
+                    self.total_fields_in_adt_variant(pat.hir_id, variant_index, pat.span)?;
+
+                for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
+                    let subpat_ty = self.pat_ty_adjusted(subpat)?;
+                    let projection_kind =
+                        ProjectionKind::Field(FieldIdx::from_usize(i), variant_index);
+                    let sub_place = self.cat_projection(
+                        pat.hir_id,
+                        place_with_id.clone(),
+                        subpat_ty,
+                        projection_kind,
+                    );
+                    self.cat_pattern(sub_place, subpat, op)?;
+                }
+            }
+
+            PatKind::Struct(ref qpath, field_pats, _) => {
+                // S { f1: p1, ..., fN: pN }
+
+                let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
+
+                for fp in field_pats {
+                    let field_ty = self.pat_ty_adjusted(fp.pat)?;
+                    let field_index = self
+                        .cx
+                        .typeck_results()
+                        .field_indices()
+                        .get(fp.hir_id)
+                        .cloned()
+                        .expect("no index for a field");
+
+                    let field_place = self.cat_projection(
+                        pat.hir_id,
+                        place_with_id.clone(),
+                        field_ty,
+                        ProjectionKind::Field(field_index, variant_index),
+                    );
+                    self.cat_pattern(field_place, fp.pat, op)?;
+                }
+            }
+
+            PatKind::Or(pats) => {
+                for pat in pats {
+                    self.cat_pattern(place_with_id.clone(), pat, op)?;
+                }
+            }
+
+            PatKind::Binding(.., Some(subpat)) => {
+                self.cat_pattern(place_with_id, subpat, op)?;
+            }
+
+            PatKind::Ref(subpat, _)
+                if self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id) =>
+            {
+                self.cat_pattern(place_with_id, subpat, op)?;
+            }
+
+            PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
+                // box p1, &p1, &mut p1. we can ignore the mutability of
+                // PatKind::Ref since that information is already contained
+                // in the type.
+                let subplace = self.cat_deref(pat.hir_id, place_with_id)?;
+                self.cat_pattern(subplace, subpat, op)?;
+            }
+            PatKind::Deref(subpat) => {
+                let mutable = self.cx.typeck_results().pat_has_ref_mut_binding(subpat);
+                let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
+                let re_erased = self.cx.tcx().lifetimes.re_erased;
+                let ty = self.pat_ty_adjusted(subpat)?;
+                let ty = Ty::new_ref(self.cx.tcx(), re_erased, ty, mutability);
+                // A deref pattern generates a temporary.
+                let place = self.cat_rvalue(pat.hir_id, ty);
+                self.cat_pattern(place, subpat, op)?;
+            }
+
+            PatKind::Slice(before, ref slice, after) => {
+                let Some(element_ty) = place_with_id.place.ty().builtin_index() else {
+                    debug!("explicit index of non-indexable type {:?}", place_with_id);
+                    return Err(self
+                        .cx
+                        .report_error(pat.span, "explicit index of non-indexable type"));
+                };
+                let elt_place = self.cat_projection(
+                    pat.hir_id,
+                    place_with_id.clone(),
+                    element_ty,
+                    ProjectionKind::Index,
+                );
+                for before_pat in before {
+                    self.cat_pattern(elt_place.clone(), before_pat, op)?;
+                }
+                if let Some(slice_pat) = *slice {
+                    let slice_pat_ty = self.pat_ty_adjusted(slice_pat)?;
+                    let slice_place = self.cat_projection(
+                        pat.hir_id,
+                        place_with_id,
+                        slice_pat_ty,
+                        ProjectionKind::Subslice,
+                    );
+                    self.cat_pattern(slice_place, slice_pat, op)?;
+                }
+                for after_pat in after {
+                    self.cat_pattern(elt_place.clone(), after_pat, op)?;
+                }
+            }
+
+            PatKind::Path(_)
+            | PatKind::Binding(.., None)
+            | PatKind::Lit(..)
+            | PatKind::Range(..)
+            | PatKind::Never
+            | PatKind::Wild
+            | PatKind::Err(_) => {
+                // always ok
+            }
+        }
+
+        Ok(())
+    }
+
+    fn is_multivariant_adt(&self, ty: Ty<'tcx>, span: Span) -> bool {
+        if let ty::Adt(def, _) = self.cx.try_structurally_resolve_type(span, ty).kind() {
+            // Note that if a non-exhaustive SingleVariant is defined in another crate, we need
+            // to assume that more cases will be added to the variant in the future. This mean
+            // that we should handle non-exhaustive SingleVariant the same way we would handle
+            // a MultiVariant.
+            // If the variant is not local it must be defined in another crate.
+            let is_non_exhaustive = match def.adt_kind() {
+                AdtKind::Struct | AdtKind::Union => {
+                    def.non_enum_variant().is_field_list_non_exhaustive()
+                }
+                AdtKind::Enum => def.is_variant_list_non_exhaustive(),
+            };
+            def.variants().len() > 1 || (!def.did().is_local() && is_non_exhaustive)
+        } else {
+            false
+        }
     }
 }
diff --git a/compiler/rustc_hir_typeck/src/fallback.rs b/compiler/rustc_hir_typeck/src/fallback.rs
index f240a53..e8533c6 100644
--- a/compiler/rustc_hir_typeck/src/fallback.rs
+++ b/compiler/rustc_hir_typeck/src/fallback.rs
@@ -9,6 +9,7 @@
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::HirId;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
+use rustc_middle::bug;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable};
 use rustc_session::lint;
 use rustc_span::DUMMY_SP;
@@ -363,41 +364,11 @@
             };
 
             let mut fallback_to = |ty| {
-                let unsafe_infer_vars = unsafe_infer_vars.get_or_init(|| {
-                    let unsafe_infer_vars = compute_unsafe_infer_vars(self.root_ctxt, self.body_id);
-                    debug!(?unsafe_infer_vars);
-                    unsafe_infer_vars
-                });
-
-                let affected_unsafe_infer_vars =
-                    graph::depth_first_search_as_undirected(&coercion_graph, root_vid)
-                        .filter_map(|x| unsafe_infer_vars.get(&x).copied())
-                        .collect::<Vec<_>>();
-
-                for (hir_id, span, reason) in affected_unsafe_infer_vars {
-                    self.tcx.emit_node_span_lint(
-                        lint::builtin::NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
-                        hir_id,
-                        span,
-                        match reason {
-                            UnsafeUseReason::Call => {
-                                errors::NeverTypeFallbackFlowingIntoUnsafe::Call
-                            }
-                            UnsafeUseReason::Method => {
-                                errors::NeverTypeFallbackFlowingIntoUnsafe::Method
-                            }
-                            UnsafeUseReason::Path => {
-                                errors::NeverTypeFallbackFlowingIntoUnsafe::Path
-                            }
-                            UnsafeUseReason::UnionField => {
-                                errors::NeverTypeFallbackFlowingIntoUnsafe::UnionField
-                            }
-                            UnsafeUseReason::Deref => {
-                                errors::NeverTypeFallbackFlowingIntoUnsafe::Deref
-                            }
-                        },
-                    );
-                }
+                self.lint_never_type_fallback_flowing_into_unsafe_code(
+                    &unsafe_infer_vars,
+                    &coercion_graph,
+                    root_vid,
+                );
 
                 diverging_fallback.insert(diverging_ty, ty);
             };
@@ -463,6 +434,41 @@
         diverging_fallback
     }
 
+    fn lint_never_type_fallback_flowing_into_unsafe_code(
+        &self,
+        unsafe_infer_vars: &OnceCell<UnordMap<ty::TyVid, (HirId, Span, UnsafeUseReason)>>,
+        coercion_graph: &VecGraph<ty::TyVid, true>,
+        root_vid: ty::TyVid,
+    ) {
+        let unsafe_infer_vars = unsafe_infer_vars.get_or_init(|| {
+            let unsafe_infer_vars = compute_unsafe_infer_vars(self.root_ctxt, self.body_id);
+            debug!(?unsafe_infer_vars);
+            unsafe_infer_vars
+        });
+
+        let affected_unsafe_infer_vars =
+            graph::depth_first_search_as_undirected(&coercion_graph, root_vid)
+                .filter_map(|x| unsafe_infer_vars.get(&x).copied())
+                .collect::<Vec<_>>();
+
+        for (hir_id, span, reason) in affected_unsafe_infer_vars {
+            self.tcx.emit_node_span_lint(
+                lint::builtin::NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
+                hir_id,
+                span,
+                match reason {
+                    UnsafeUseReason::Call => errors::NeverTypeFallbackFlowingIntoUnsafe::Call,
+                    UnsafeUseReason::Method => errors::NeverTypeFallbackFlowingIntoUnsafe::Method,
+                    UnsafeUseReason::Path => errors::NeverTypeFallbackFlowingIntoUnsafe::Path,
+                    UnsafeUseReason::UnionField => {
+                        errors::NeverTypeFallbackFlowingIntoUnsafe::UnionField
+                    }
+                    UnsafeUseReason::Deref => errors::NeverTypeFallbackFlowingIntoUnsafe::Deref,
+                },
+            );
+        }
+    }
+
     /// Returns a graph whose nodes are (unresolved) inference variables and where
     /// an edge `?A -> ?B` indicates that the variable `?A` is coerced to `?B`.
     fn create_coercion_graph(&self) -> VecGraph<ty::TyVid, true> {
@@ -557,7 +563,7 @@
                     if let Some(def_id) = typeck_results.type_dependent_def_id(ex.hir_id)
                         && let method_ty = self.root_ctxt.tcx.type_of(def_id).instantiate_identity()
                         && let sig = method_ty.fn_sig(self.root_ctxt.tcx)
-                        && let hir::Unsafety::Unsafe = sig.unsafety()
+                        && let hir::Safety::Unsafe = sig.safety()
                     {
                         let mut collector = InferVarCollector {
                             value: (ex.hir_id, ex.span, UnsafeUseReason::Method),
@@ -577,7 +583,7 @@
 
                     if func_ty.is_fn()
                         && let sig = func_ty.fn_sig(self.root_ctxt.tcx)
-                        && let hir::Unsafety::Unsafe = sig.unsafety()
+                        && let hir::Safety::Unsafe = sig.safety()
                     {
                         let mut collector = InferVarCollector {
                             value: (ex.hir_id, ex.span, UnsafeUseReason::Call),
@@ -608,7 +614,7 @@
                     // `is_fn` excludes closures, but those can't be unsafe.
                     if ty.is_fn()
                         && let sig = ty.fn_sig(self.root_ctxt.tcx)
-                        && let hir::Unsafety::Unsafe = sig.unsafety()
+                        && let hir::Safety::Unsafe = sig.safety()
                     {
                         let mut collector = InferVarCollector {
                             value: (ex.hir_id, ex.span, UnsafeUseReason::Path),
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 552747b..77f90c0 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -29,10 +29,11 @@
     self, AdtKind, CanonicalUserType, GenericParamDefKind, IsIdentity, Ty, TyCtxt, UserType,
 };
 use rustc_middle::ty::{GenericArgKind, GenericArgsRef, UserArgs, UserSelfTy};
+use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::hygiene::DesugaringKind;
-use rustc_span::symbol::{kw, sym, Ident};
+use rustc_span::symbol::{kw, sym};
 use rustc_span::Span;
 use rustc_target::abi::FieldIdx;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
@@ -409,7 +410,7 @@
 
     pub fn lower_ty(&self, hir_ty: &hir::Ty<'tcx>) -> LoweredTy<'tcx> {
         let ty = self.lowerer().lower_ty(hir_ty);
-        self.register_wf_obligation(ty.into(), hir_ty.span, traits::WellFormed(None));
+        self.register_wf_obligation(ty.into(), hir_ty.span, ObligationCauseCode::WellFormed(None));
         LoweredTy::from_raw(self, hir_ty.span, ty)
     }
 
@@ -520,7 +521,7 @@
         for arg in args.iter().filter(|arg| {
             matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
         }) {
-            self.register_wf_obligation(arg, expr.span, traits::WellFormed(None));
+            self.register_wf_obligation(arg, expr.span, ObligationCauseCode::WellFormed(None));
         }
     }
 
@@ -624,10 +625,7 @@
     /// returns a type of `&T`, but the actual type we assign to the
     /// *expression* is `T`. So this function just peels off the return
     /// type by one layer to yield `T`.
-    pub(crate) fn make_overloaded_place_return_type(
-        &self,
-        method: MethodCallee<'tcx>,
-    ) -> ty::TypeAndMut<'tcx> {
+    pub(crate) fn make_overloaded_place_return_type(&self, method: MethodCallee<'tcx>) -> Ty<'tcx> {
         // extract method return type, which will be &T;
         let ret_ty = method.sig.output();
 
@@ -775,7 +773,11 @@
         };
         if let Some(&cached_result) = self.typeck_results.borrow().type_dependent_defs().get(hir_id)
         {
-            self.register_wf_obligation(ty.raw.into(), qself.span, traits::WellFormed(None));
+            self.register_wf_obligation(
+                ty.raw.into(),
+                qself.span,
+                ObligationCauseCode::WellFormed(None),
+            );
             // Return directly on cache hit. This is useful to avoid doubly reporting
             // errors with default match binding modes. See #44614.
             let def = cached_result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id));
@@ -814,7 +816,7 @@
                     self.register_wf_obligation(
                         ty.raw.into(),
                         qself.span,
-                        traits::WellFormed(None),
+                        ObligationCauseCode::WellFormed(None),
                     );
                 }
 
@@ -832,6 +834,7 @@
                 if item_name.name != kw::Empty {
                     if let Some(e) = self.report_method_error(
                         span,
+                        None,
                         ty.normalized,
                         item_name,
                         SelfSource::QPath(qself),
@@ -848,7 +851,11 @@
             });
 
         if result.is_ok() {
-            self.register_wf_obligation(ty.raw.into(), qself.span, traits::WellFormed(None));
+            self.register_wf_obligation(
+                ty.raw.into(),
+                qself.span,
+                ObligationCauseCode::WellFormed(None),
+            );
         }
 
         // Write back the new resolution.
@@ -860,76 +867,6 @@
         )
     }
 
-    /// Given a function `Node`, return its  `HirId` and `FnDecl` if it exists. Given a closure
-    /// that is the child of a function, return that function's `HirId` and `FnDecl` instead.
-    /// This may seem confusing at first, but this is used in diagnostics for `async fn`,
-    /// for example, where most of the type checking actually happens within a nested closure,
-    /// but we often want access to the parent function's signature.
-    ///
-    /// Otherwise, return false.
-    pub(crate) fn get_node_fn_decl(
-        &self,
-        node: Node<'tcx>,
-    ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, Ident, bool)> {
-        match node {
-            Node::Item(&hir::Item {
-                ident,
-                kind: hir::ItemKind::Fn(ref sig, ..),
-                owner_id,
-                ..
-            }) => {
-                // This is less than ideal, it will not suggest a return type span on any
-                // method called `main`, regardless of whether it is actually the entry point,
-                // but it will still present it as the reason for the expected type.
-                Some((owner_id.def_id, &sig.decl, ident, ident.name != sym::main))
-            }
-            Node::TraitItem(&hir::TraitItem {
-                ident,
-                kind: hir::TraitItemKind::Fn(ref sig, ..),
-                owner_id,
-                ..
-            }) => Some((owner_id.def_id, &sig.decl, ident, true)),
-            Node::ImplItem(&hir::ImplItem {
-                ident,
-                kind: hir::ImplItemKind::Fn(ref sig, ..),
-                owner_id,
-                ..
-            }) => Some((owner_id.def_id, &sig.decl, ident, false)),
-            Node::Expr(&hir::Expr {
-                hir_id,
-                kind:
-                    hir::ExprKind::Closure(hir::Closure {
-                        kind: hir::ClosureKind::Coroutine(..), ..
-                    }),
-                ..
-            }) => {
-                let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
-                    Node::Item(&hir::Item {
-                        ident,
-                        kind: hir::ItemKind::Fn(ref sig, ..),
-                        owner_id,
-                        ..
-                    }) => (ident, sig, owner_id),
-                    Node::TraitItem(&hir::TraitItem {
-                        ident,
-                        kind: hir::TraitItemKind::Fn(ref sig, ..),
-                        owner_id,
-                        ..
-                    }) => (ident, sig, owner_id),
-                    Node::ImplItem(&hir::ImplItem {
-                        ident,
-                        kind: hir::ImplItemKind::Fn(ref sig, ..),
-                        owner_id,
-                        ..
-                    }) => (ident, sig, owner_id),
-                    _ => return None,
-                };
-                Some((owner_id.def_id, &sig.decl, ident, ident.name != sym::main))
-            }
-            _ => None,
-        }
-    }
-
     /// Given a `HirId`, return the `HirId` of the enclosing function, its `FnDecl`, and whether a
     /// suggestion can be made, `None` otherwise.
     pub fn get_fn_decl(
@@ -938,10 +875,73 @@
     ) -> Option<(LocalDefId, &'tcx hir::FnDecl<'tcx>, bool)> {
         // Get enclosing Fn, if it is a function or a trait method, unless there's a `loop` or
         // `while` before reaching it, as block tail returns are not available in them.
-        self.tcx.hir().get_return_block(blk_id).and_then(|blk_id| {
-            let parent = self.tcx.hir_node(blk_id);
-            self.get_node_fn_decl(parent)
-                .map(|(fn_id, fn_decl, _, is_main)| (fn_id, fn_decl, is_main))
+        self.tcx.hir().get_fn_id_for_return_block(blk_id).and_then(|item_id| {
+            match self.tcx.hir_node(item_id) {
+                Node::Item(&hir::Item {
+                    ident,
+                    kind: hir::ItemKind::Fn(ref sig, ..),
+                    owner_id,
+                    ..
+                }) => {
+                    // This is less than ideal, it will not suggest a return type span on any
+                    // method called `main`, regardless of whether it is actually the entry point,
+                    // but it will still present it as the reason for the expected type.
+                    Some((owner_id.def_id, sig.decl, ident.name != sym::main))
+                }
+                Node::TraitItem(&hir::TraitItem {
+                    kind: hir::TraitItemKind::Fn(ref sig, ..),
+                    owner_id,
+                    ..
+                }) => Some((owner_id.def_id, sig.decl, true)),
+                // FIXME: Suggestable if this is not a trait implementation
+                Node::ImplItem(&hir::ImplItem {
+                    kind: hir::ImplItemKind::Fn(ref sig, ..),
+                    owner_id,
+                    ..
+                }) => Some((owner_id.def_id, sig.decl, false)),
+                Node::Expr(&hir::Expr {
+                    hir_id,
+                    kind: hir::ExprKind::Closure(&hir::Closure { def_id, kind, fn_decl, .. }),
+                    ..
+                }) => {
+                    match kind {
+                        hir::ClosureKind::CoroutineClosure(_) => {
+                            // FIXME(async_closures): Implement this.
+                            return None;
+                        }
+                        hir::ClosureKind::Closure => Some((def_id, fn_decl, true)),
+                        hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
+                            _,
+                            hir::CoroutineSource::Fn,
+                        )) => {
+                            let (ident, sig, owner_id) = match self.tcx.parent_hir_node(hir_id) {
+                                Node::Item(&hir::Item {
+                                    ident,
+                                    kind: hir::ItemKind::Fn(ref sig, ..),
+                                    owner_id,
+                                    ..
+                                }) => (ident, sig, owner_id),
+                                Node::TraitItem(&hir::TraitItem {
+                                    ident,
+                                    kind: hir::TraitItemKind::Fn(ref sig, ..),
+                                    owner_id,
+                                    ..
+                                }) => (ident, sig, owner_id),
+                                Node::ImplItem(&hir::ImplItem {
+                                    ident,
+                                    kind: hir::ImplItemKind::Fn(ref sig, ..),
+                                    owner_id,
+                                    ..
+                                }) => (ident, sig, owner_id),
+                                _ => return None,
+                            };
+                            Some((owner_id.def_id, sig.decl, ident.name != sym::main))
+                        }
+                        _ => None,
+                    }
+                }
+                _ => None,
+            }
         })
     }
 
@@ -1404,11 +1404,7 @@
         hir_id: HirId,
     ) {
         self.add_required_obligations_with_code(span, def_id, args, |idx, span| {
-            if span.is_dummy() {
-                ObligationCauseCode::ExprItemObligation(def_id, hir_id, idx)
-            } else {
-                ObligationCauseCode::ExprBindingObligation(def_id, span, hir_id, idx)
-            }
+            ObligationCauseCode::WhereClauseInExpr(def_id, span, hir_id, idx)
         })
     }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index a718760..4edc11d 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -14,8 +14,7 @@
         &self,
         error: &mut traits::FulfillmentError<'tcx>,
     ) -> bool {
-        let (traits::ExprItemObligation(def_id, hir_id, idx)
-        | traits::ExprBindingObligation(def_id, _, hir_id, idx)) =
+        let ObligationCauseCode::WhereClauseInExpr(def_id, _, hir_id, idx) =
             *error.obligation.cause.code().peel_derives()
         else {
             return false;
@@ -38,7 +37,7 @@
                 ty::ClauseKind::Trait(pred) => {
                     (pred.trait_ref.args.to_vec(), Some(pred.self_ty().into()))
                 }
-                ty::ClauseKind::Projection(pred) => (pred.projection_ty.args.to_vec(), None),
+                ty::ClauseKind::Projection(pred) => (pred.projection_term.args.to_vec(), None),
                 ty::ClauseKind::ConstArgHasType(arg, ty) => (vec![ty.into(), arg.into()], None),
                 ty::ClauseKind::ConstEvaluatable(e) => (vec![e.into()], None),
                 _ => return false,
@@ -167,7 +166,7 @@
                     // the method's turbofish segments but still use `FunctionArgumentObligation`
                     // elsewhere. Hopefully this doesn't break something.
                     error.obligation.cause.map_code(|parent_code| {
-                        ObligationCauseCode::FunctionArgumentObligation {
+                        ObligationCauseCode::FunctionArg {
                             arg_hir_id: receiver.hir_id,
                             call_hir_id: hir_id,
                             parent_code,
@@ -360,12 +359,9 @@
         error: &traits::FulfillmentError<'tcx>,
         span: Span,
     ) -> bool {
-        if let traits::FulfillmentErrorCode::SelectionError(
-            traits::SelectionError::SignatureMismatch(box traits::SignatureMismatchData {
-                expected_trait_ref,
-                ..
-            }),
-        ) = error.code
+        if let traits::FulfillmentErrorCode::Select(traits::SelectionError::SignatureMismatch(
+            box traits::SignatureMismatchData { expected_trait_ref, .. },
+        )) = error.code
             && let ty::Closure(def_id, _) | ty::Coroutine(def_id, ..) =
                 expected_trait_ref.self_ty().kind()
             && span.overlaps(self.tcx.def_span(*def_id))
@@ -459,12 +455,10 @@
                 self.blame_specific_expr_if_possible(error, arg_expr)
             }
 
-            error.obligation.cause.map_code(|parent_code| {
-                ObligationCauseCode::FunctionArgumentObligation {
-                    arg_hir_id: arg.hir_id,
-                    call_hir_id,
-                    parent_code,
-                }
+            error.obligation.cause.map_code(|parent_code| ObligationCauseCode::FunctionArg {
+                arg_hir_id: arg.hir_id,
+                call_hir_id,
+                parent_code,
             });
             return true;
         } else if args_referencing_param.len() > 0 {
@@ -517,12 +511,12 @@
         expr: &'tcx hir::Expr<'tcx>,
     ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
         match obligation_cause_code {
-            traits::ObligationCauseCode::ExprBindingObligation(_, _, _, _) => {
+            traits::ObligationCauseCode::WhereClauseInExpr(_, _, _, _) => {
                 // This is the "root"; we assume that the `expr` is already pointing here.
                 // Therefore, we return `Ok` so that this `expr` can be refined further.
                 Ok(expr)
             }
-            traits::ObligationCauseCode::ImplDerivedObligation(impl_derived) => self
+            traits::ObligationCauseCode::ImplDerived(impl_derived) => self
                 .blame_specific_expr_if_possible_for_derived_predicate_obligation(
                     impl_derived,
                     expr,
@@ -560,7 +554,7 @@
     /// only a partial success - but it cannot be refined even further.
     fn blame_specific_expr_if_possible_for_derived_predicate_obligation(
         &self,
-        obligation: &traits::ImplDerivedObligationCause<'tcx>,
+        obligation: &traits::ImplDerivedCause<'tcx>,
         expr: &'tcx hir::Expr<'tcx>,
     ) -> Result<&'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>> {
         // First, we attempt to refine the `expr` for our span using the parent obligation.
@@ -729,7 +723,7 @@
             };
 
             let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did());
-            if drill_generic_index >= struct_generic_parameters.params.len() {
+            if drill_generic_index >= struct_generic_parameters.own_params.len() {
                 return Err(expr);
             }
 
@@ -852,7 +846,7 @@
             };
 
             let struct_generic_parameters: &ty::Generics = self.tcx.generics_of(in_ty_adt.did());
-            if drill_generic_index >= struct_generic_parameters.params.len() {
+            if drill_generic_index >= struct_generic_parameters.own_params.len() {
                 return Err(expr);
             }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index e45e088..b8333d4 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -31,16 +31,15 @@
 use rustc_hir_analysis::structured_errors::StructuredDiag;
 use rustc_index::IndexVec;
 use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::TypeTrace;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
-use rustc_middle::traits::ObligationCauseCode::ExprBindingObligation;
 use rustc_middle::ty::adjustment::AllowTwoPhase;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_session::Session;
 use rustc_span::symbol::{kw, Ident};
-use rustc_span::{sym, BytePos, Span};
+use rustc_span::{sym, BytePos, Span, DUMMY_SP};
 use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext};
 
 use std::iter;
@@ -204,7 +203,11 @@
         // All the input types from the fn signature must outlive the call
         // so as to validate implied bounds.
         for (&fn_input_ty, arg_expr) in iter::zip(formal_input_tys, provided_args) {
-            self.register_wf_obligation(fn_input_ty.into(), arg_expr.span, traits::MiscObligation);
+            self.register_wf_obligation(
+                fn_input_ty.into(),
+                arg_expr.span,
+                ObligationCauseCode::Misc,
+            );
         }
 
         let mut err_code = E0061;
@@ -1771,7 +1774,7 @@
                     // that highlight errors inline.
                     let mut sp = blk.span;
                     let mut fn_span = None;
-                    if let Some((decl, ident)) = self.get_parent_fn_decl(blk.hir_id) {
+                    if let Some((fn_def_id, decl, _)) = self.get_fn_decl(blk.hir_id) {
                         let ret_sp = decl.output.span();
                         if let Some(block_sp) = self.parent_item_span(blk.hir_id) {
                             // HACK: on some cases (`ui/liveness/liveness-issue-2163.rs`) the
@@ -1779,7 +1782,7 @@
                             // the span we're aiming at correspond to a `fn` body.
                             if block_sp == blk.span {
                                 sp = ret_sp;
-                                fn_span = Some(ident.span);
+                                fn_span = self.tcx.def_ident_span(fn_def_id);
                             }
                         }
                     }
@@ -1894,15 +1897,6 @@
         None
     }
 
-    /// Given a function block's `HirId`, returns its `FnDecl` if it exists, or `None` otherwise.
-    pub(crate) fn get_parent_fn_decl(
-        &self,
-        blk_id: HirId,
-    ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident)> {
-        let parent = self.tcx.hir_node_by_def_id(self.tcx.hir().get_parent_item(blk_id).def_id);
-        self.get_node_fn_decl(parent).map(|(_, fn_decl, ident, _)| (fn_decl, ident))
-    }
-
     /// If `expr` is a `match` expression that has only one non-`!` arm, use that arm's tail
     /// expression's `Span`, otherwise return `expr.span`. This is done to give better errors
     /// when given code like the following:
@@ -2011,7 +2005,7 @@
         for (span, code) in errors_causecode {
             self.dcx().try_steal_modify_and_emit_err(span, StashKey::MaybeForgetReturn, |err| {
                 if let Some(fn_sig) = self.body_fn_sig()
-                    && let ExprBindingObligation(_, _, binding_hir_id, ..) = code
+                    && let ObligationCauseCode::WhereClauseInExpr(_, _, binding_hir_id, ..) = code
                     && !fn_sig.output().is_unit()
                 {
                     let mut block_num = 0;
@@ -2100,7 +2094,7 @@
         //
         // This is because due to normalization, we often register duplicate
         // obligations with misc obligations that are basically impossible to
-        // line back up with a useful ExprBindingObligation.
+        // line back up with a useful WhereClauseInExpr.
         for error in not_adjusted {
             for (span, predicate, cause) in &remap_cause {
                 if *predicate == error.obligation.predicate
@@ -2180,13 +2174,7 @@
                         let trait_ref = ty::TraitRef::new(
                             self.tcx,
                             self.tcx.fn_trait_kind_to_def_id(call_kind)?,
-                            [
-                                callee_ty,
-                                self.next_ty_var(TypeVariableOrigin {
-                                    param_def_id: None,
-                                    span: rustc_span::DUMMY_SP,
-                                }),
-                            ],
+                            [callee_ty, self.next_ty_var(DUMMY_SP)],
                         );
                         let obligation = traits::Obligation::new(
                             self.tcx,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
index c2068d9..23f4d3c 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/inspect_obligations.rs
@@ -1,9 +1,8 @@
 //! A utility module to inspect currently ambiguous obligations in the current context.
-use crate::rustc_middle::ty::TypeVisitableExt;
 use crate::FnCtxt;
-use rustc_infer::traits::solve::Goal;
 use rustc_infer::traits::{self, ObligationCause};
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::traits::solve::Goal;
+use rustc_middle::ty::{self, Ty, TypeVisitableExt};
 use rustc_span::Span;
 use rustc_trait_selection::solve::inspect::ProofTreeInferCtxtExt;
 use rustc_trait_selection::solve::inspect::{InspectConfig, InspectGoal, ProofTreeVisitor};
@@ -39,7 +38,7 @@
                 self.type_matches_expected_vid(expected_vid, data.self_ty())
             }
             ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
-                self.type_matches_expected_vid(expected_vid, data.projection_ty.self_ty())
+                self.type_matches_expected_vid(expected_vid, data.projection_term.self_ty())
             }
             ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..))
             | ty::PredicateKind::Subtype(..)
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 794b854..afba812 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -19,8 +19,6 @@
 use rustc_infer::infer;
 use rustc_infer::infer::error_reporting::sub_relations::SubRelations;
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
-use rustc_middle::infer::unify_key::ConstVariableOrigin;
 use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
@@ -156,7 +154,7 @@
     }
 
     pub fn misc(&self, span: Span) -> ObligationCause<'tcx> {
-        self.cause(span, ObligationCauseCode::MiscObligation)
+        self.cause(span, ObligationCauseCode::Misc)
     }
 
     pub fn sess(&self) -> &Session {
@@ -239,7 +237,7 @@
     fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
         match param {
             Some(param) => self.var_for_def(span, param).as_type().unwrap(),
-            None => self.next_ty_var(TypeVariableOrigin { param_def_id: None, span }),
+            None => self.next_ty_var(span),
         }
     }
 
@@ -258,7 +256,7 @@
                 },
             ) => self.var_for_effect(param).as_const().unwrap(),
             Some(param) => self.var_for_def(span, param).as_const().unwrap(),
-            None => self.next_const_var(ty, ConstVariableOrigin { span, param_def_id: None }),
+            None => self.next_const_var(ty, span),
         }
     }
 
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index d00fea4..cfd4dd4 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -6,7 +6,6 @@
 use crate::hir::is_range_literal;
 use crate::method::probe;
 use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
-use crate::rustc_middle::ty::Article;
 use core::cmp::min;
 use core::iter;
 use hir::def_id::LocalDefId;
@@ -26,10 +25,11 @@
 use rustc_infer::traits;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::middle::stability::EvalResult;
+use rustc_middle::span_bug;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
-    self, suggest_constraining_type_params, Binder, IsSuggestable, ToPredicate, Ty,
-    TypeVisitableExt,
+    self, suggest_constraining_type_params, Article, Binder, IsSuggestable, Ty, TypeVisitableExt,
+    Upcast,
 };
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
@@ -290,7 +290,8 @@
         expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
     ) -> bool {
         let expr = expr.peel_blocks();
-        let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
+        let methods =
+            self.get_conversion_methods_for_diagnostic(expr.span, expected, found, expr.hir_id);
 
         if let Some((suggestion, msg, applicability, verbose, annotation)) =
             self.suggest_deref_or_ref(expr, found, expected)
@@ -799,6 +800,13 @@
         can_suggest: bool,
         fn_id: LocalDefId,
     ) -> bool {
+        // Can't suggest `->` on a block-like coroutine
+        if let Some(hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Block)) =
+            self.tcx.coroutine_kind(fn_id)
+        {
+            return false;
+        }
+
         let found =
             self.resolve_numeric_literals_with_default(self.resolve_vars_if_possible(found));
         // Only suggest changing the return type for methods that
@@ -1701,7 +1709,7 @@
                         }
                     }
                     for error in errors {
-                        if let traits::FulfillmentErrorCode::SelectionError(
+                        if let traits::FulfillmentErrorCode::Select(
                             traits::SelectionError::Unimplemented,
                         ) = error.code
                             && let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
@@ -1715,7 +1723,7 @@
                         }
                     }
                 }
-                self.suggest_derive(diag, &[(trait_ref.to_predicate(self.tcx), None, None)]);
+                self.suggest_derive(diag, &[(trait_ref.upcast(self.tcx), None, None)]);
             }
         }
     }
@@ -1908,7 +1916,7 @@
         let returned = matches!(
             self.tcx.parent_hir_node(expr.hir_id),
             hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
-        ) || map.get_return_block(expr.hir_id).is_some();
+        ) || map.get_fn_id_for_return_block(expr.hir_id).is_some();
         if returned
             && let ty::Adt(e, args_e) = expected.kind()
             && let ty::Adt(f, args_f) = found.kind()
@@ -2227,7 +2235,7 @@
     ) -> bool {
         let tcx = self.tcx;
         let (adt, args, unwrap) = match expected.kind() {
-            // In case Option<NonZero*> is wanted, but * is provided, suggest calling new
+            // In case `Option<NonZero<T>>` is wanted, but `T` is provided, suggest calling `new`.
             ty::Adt(adt, args) if tcx.is_diagnostic_item(sym::Option, adt.did()) => {
                 let nonzero_type = args.type_at(0); // Unwrap option type.
                 let ty::Adt(adt, args) = nonzero_type.kind() else {
@@ -2235,7 +2243,7 @@
                 };
                 (adt, args, "")
             }
-            // In case `NonZero<*>` is wanted but `*` is provided, also add `.unwrap()` to satisfy types.
+            // In case `NonZero<T>` is wanted but `T` is provided, also add `.unwrap()` to satisfy types.
             ty::Adt(adt, args) => (adt, args, ".unwrap()"),
             _ => return false,
         };
@@ -2244,32 +2252,15 @@
             return false;
         }
 
-        // FIXME: This can be simplified once `NonZero<T>` is stable.
-        let coercable_types = [
-            ("NonZeroU8", tcx.types.u8),
-            ("NonZeroU16", tcx.types.u16),
-            ("NonZeroU32", tcx.types.u32),
-            ("NonZeroU64", tcx.types.u64),
-            ("NonZeroU128", tcx.types.u128),
-            ("NonZeroI8", tcx.types.i8),
-            ("NonZeroI16", tcx.types.i16),
-            ("NonZeroI32", tcx.types.i32),
-            ("NonZeroI64", tcx.types.i64),
-            ("NonZeroI128", tcx.types.i128),
-        ];
-
         let int_type = args.type_at(0);
-
-        let Some(nonzero_alias) = coercable_types.iter().find_map(|(nonzero_alias, t)| {
-            if *t == int_type && self.can_coerce(expr_ty, *t) { Some(nonzero_alias) } else { None }
-        }) else {
+        if !self.can_coerce(expr_ty, int_type) {
             return false;
-        };
+        }
 
         err.multipart_suggestion(
-            format!("consider calling `{nonzero_alias}::new`"),
+            format!("consider calling `{}::new`", sym::NonZero),
             vec![
-                (expr.span.shrink_to_lo(), format!("{nonzero_alias}::new(")),
+                (expr.span.shrink_to_lo(), format!("{}::new(", sym::NonZero)),
                 (expr.span.shrink_to_hi(), format!("){unwrap}")),
             ],
             Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_hir_typeck/src/gather_locals.rs b/compiler/rustc_hir_typeck/src/gather_locals.rs
index fe0a469..13e4b62 100644
--- a/compiler/rustc_hir_typeck/src/gather_locals.rs
+++ b/compiler/rustc_hir_typeck/src/gather_locals.rs
@@ -2,12 +2,11 @@
 use rustc_hir as hir;
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{HirId, PatKind};
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
+use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::ty::Ty;
 use rustc_middle::ty::UserType;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
-use rustc_trait_selection::traits;
 
 /// Provides context for checking patterns in declarations. More specifically this
 /// allows us to infer array types if the pattern is irrefutable and allows us to infer
@@ -50,7 +49,7 @@
 
 impl<'a> From<(&'a hir::LetExpr<'a>, HirId)> for Declaration<'a> {
     fn from((let_expr, hir_id): (&'a hir::LetExpr<'a>, HirId)) -> Self {
-        let hir::LetExpr { pat, ty, span, init, is_recovered: _ } = *let_expr;
+        let hir::LetExpr { pat, ty, span, init, recovered: _ } = *let_expr;
         Declaration { hir_id, pat, ty, span, init: Some(init), origin: DeclOrigin::LetExpr }
     }
 }
@@ -72,7 +71,7 @@
         match ty_opt {
             None => {
                 // Infer the variable's type.
-                let var_ty = self.fcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span });
+                let var_ty = self.fcx.next_ty_var(span);
                 self.fcx.locals.borrow_mut().insert(nid, var_ty);
                 var_ty
             }
@@ -147,7 +146,7 @@
                         p.span,
                         // ty_span == ident.span iff this is a closure parameter with no type
                         // ascription, or if it's an implicit `self` parameter
-                        traits::SizedArgumentType(
+                        ObligationCauseCode::SizedArgumentType(
                             if ty_span == ident.span
                                 && self.fcx.tcx.is_closure_like(self.fcx.body_id.into())
                             {
@@ -160,7 +159,11 @@
                 }
             } else {
                 if !self.fcx.tcx.features().unsized_locals {
-                    self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id));
+                    self.fcx.require_type_is_sized(
+                        var_ty,
+                        p.span,
+                        ObligationCauseCode::VariableType(p.hir_id),
+                    );
                 }
             }
 
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 62711e4..fb8863c 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -2,6 +2,7 @@
 use rustc_errors::{codes::*, struct_span_code_err};
 use rustc_hir as hir;
 use rustc_index::Idx;
+use rustc_middle::bug;
 use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
 use rustc_target::abi::{Pointer, VariantIdx};
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 8bc070b..b9a99fb 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -10,9 +10,6 @@
 #[macro_use]
 extern crate tracing;
 
-#[macro_use]
-extern crate rustc_middle;
-
 mod _match;
 mod autoderef;
 mod callee;
@@ -32,7 +29,6 @@
 mod fn_ctxt;
 mod gather_locals;
 mod intrinsicck;
-mod mem_categorization;
 mod method;
 mod op;
 mod pat;
@@ -60,11 +56,10 @@
 use rustc_hir::{HirId, HirIdMap, Node};
 use rustc_hir_analysis::check::check_abi;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::traits::{ObligationCauseCode, ObligationInspector, WellFormedLoc};
 use rustc_middle::query::Providers;
-use rustc_middle::traits;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_session::config;
 use rustc_span::def_id::LocalDefId;
 use rustc_span::Span;
@@ -150,7 +145,7 @@
 
     if let Some(hir::FnSig { header, decl, .. }) = node.fn_sig() {
         let fn_sig = if decl.output.get_infer_ret_ty().is_some() {
-            fcx.lowerer().lower_fn_ty(id, header.unsafety, header.abi, decl, None, None)
+            fcx.lowerer().lower_fn_ty(id, header.safety, header.abi, decl, None, None)
         } else {
             tcx.fn_sig(def_id).instantiate_identity()
         };
@@ -171,7 +166,7 @@
         let wf_code = ObligationCauseCode::WellFormed(Some(WellFormedLoc::Ty(def_id)));
         fcx.register_wf_obligation(expected_type.into(), body.value.span, wf_code);
 
-        fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized);
+        fcx.require_type_is_sized(expected_type, body.value.span, ObligationCauseCode::ConstSized);
 
         // Gather locals in statics (because of block expressions).
         GatherLocalsVisitor::new(&fcx).visit_body(body);
@@ -246,7 +241,7 @@
                 tcx.impl_trait_ref(item.container_id(tcx)).unwrap().instantiate_identity().args;
             Some(tcx.type_of(trait_item).instantiate(tcx, args))
         } else {
-            Some(fcx.next_ty_var(TypeVariableOrigin { span, param_def_id: None }))
+            Some(fcx.next_ty_var(span))
         }
     } else if let Node::AnonConst(_) = node {
         let id = tcx.local_def_id_to_hir_id(def_id);
@@ -254,7 +249,7 @@
             Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref anon_const), span, .. })
                 if anon_const.hir_id == id =>
             {
-                Some(fcx.next_ty_var(TypeVariableOrigin { span, param_def_id: None }))
+                Some(fcx.next_ty_var(span))
             }
             Node::Expr(&hir::Expr { kind: hir::ExprKind::InlineAsm(asm), span, .. })
             | Node::Item(&hir::Item { kind: hir::ItemKind::GlobalAsm(asm), span, .. }) => {
@@ -264,7 +259,7 @@
                         Some(fcx.next_int_var())
                     }
                     hir::InlineAsmOperand::SymFn { anon_const } if anon_const.hir_id == id => {
-                        Some(fcx.next_ty_var(TypeVariableOrigin { span, param_def_id: None }))
+                        Some(fcx.next_ty_var(span))
                     }
                     _ => None,
                 })
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
deleted file mode 100644
index b44c234..0000000
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ /dev/null
@@ -1,774 +0,0 @@
-//! # Categorization
-//!
-//! The job of the categorization module is to analyze an expression to
-//! determine what kind of memory is used in evaluating it (for example,
-//! where dereferences occur and what kind of pointer is dereferenced;
-//! whether the memory is mutable, etc.).
-//!
-//! Categorization effectively transforms all of our expressions into
-//! expressions of the following forms (the actual enum has many more
-//! possibilities, naturally, but they are all variants of these base
-//! forms):
-//! ```ignore (not-rust)
-//! E = rvalue    // some computed rvalue
-//!   | x         // address of a local variable or argument
-//!   | *E        // deref of a ptr
-//!   | E.comp    // access to an interior component
-//! ```
-//! Imagine a routine ToAddr(Expr) that evaluates an expression and returns an
-//! address where the result is to be found. If Expr is a place, then this
-//! is the address of the place. If `Expr` is an rvalue, this is the address of
-//! some temporary spot in memory where the result is stored.
-//!
-//! Now, `cat_expr()` classifies the expression `Expr` and the address `A = ToAddr(Expr)`
-//! as follows:
-//!
-//! - `cat`: what kind of expression was this? This is a subset of the
-//!   full expression forms which only includes those that we care about
-//!   for the purpose of the analysis.
-//! - `mutbl`: mutability of the address `A`.
-//! - `ty`: the type of data found at the address `A`.
-//!
-//! The resulting categorization tree differs somewhat from the expressions
-//! themselves. For example, auto-derefs are explicit. Also, an index `a[b]` is
-//! decomposed into two operations: a dereference to reach the array data and
-//! then an index to jump forward to the relevant item.
-//!
-//! ## By-reference upvars
-//!
-//! One part of the codegen which may be non-obvious is that we translate
-//! closure upvars into the dereference of a borrowed pointer; this more closely
-//! resembles the runtime codegen. So, for example, if we had:
-//!
-//!     let mut x = 3;
-//!     let y = 5;
-//!     let inc = || x += y;
-//!
-//! Then when we categorize `x` (*within* the closure) we would yield a
-//! result of `*x'`, effectively, where `x'` is a `Categorization::Upvar` reference
-//! tied to `x`. The type of `x'` will be a borrowed pointer.
-
-use rustc_middle::hir::place::*;
-use rustc_middle::ty::adjustment;
-use rustc_middle::ty::fold::TypeFoldable;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-
-use rustc_data_structures::fx::FxIndexMap;
-use rustc_hir as hir;
-use rustc_hir::def::{CtorOf, DefKind, Res};
-use rustc_hir::def_id::LocalDefId;
-use rustc_hir::pat_util::EnumerateAndAdjustIterator;
-use rustc_hir::{HirId, PatKind};
-use rustc_infer::infer::InferCtxt;
-use rustc_span::Span;
-use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
-use rustc_trait_selection::infer::InferCtxtExt;
-
-pub(crate) trait HirNode {
-    fn hir_id(&self) -> HirId;
-}
-
-impl HirNode for hir::Expr<'_> {
-    fn hir_id(&self) -> HirId {
-        self.hir_id
-    }
-}
-
-impl HirNode for hir::Pat<'_> {
-    fn hir_id(&self) -> HirId {
-        self.hir_id
-    }
-}
-
-#[derive(Clone)]
-pub(crate) struct MemCategorizationContext<'a, 'tcx> {
-    pub(crate) typeck_results: &'a ty::TypeckResults<'tcx>,
-    infcx: &'a InferCtxt<'tcx>,
-    param_env: ty::ParamEnv<'tcx>,
-    body_owner: LocalDefId,
-    upvars: Option<&'tcx FxIndexMap<HirId, hir::Upvar>>,
-}
-
-pub(crate) type McResult<T> = Result<T, ()>;
-
-impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
-    /// Creates a `MemCategorizationContext`.
-    pub(crate) fn new(
-        infcx: &'a InferCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        body_owner: LocalDefId,
-        typeck_results: &'a ty::TypeckResults<'tcx>,
-    ) -> MemCategorizationContext<'a, 'tcx> {
-        MemCategorizationContext {
-            typeck_results,
-            infcx,
-            param_env,
-            body_owner,
-            upvars: infcx.tcx.upvars_mentioned(body_owner),
-        }
-    }
-
-    pub(crate) fn tcx(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    pub(crate) fn type_is_copy_modulo_regions(&self, ty: Ty<'tcx>) -> bool {
-        self.infcx.type_is_copy_modulo_regions(self.param_env, ty)
-    }
-
-    fn resolve_vars_if_possible<T>(&self, value: T) -> T
-    where
-        T: TypeFoldable<TyCtxt<'tcx>>,
-    {
-        self.infcx.resolve_vars_if_possible(value)
-    }
-
-    fn is_tainted_by_errors(&self) -> bool {
-        self.infcx.tainted_by_errors().is_some()
-    }
-
-    fn resolve_type_vars_or_error(&self, id: HirId, ty: Option<Ty<'tcx>>) -> McResult<Ty<'tcx>> {
-        match ty {
-            Some(ty) => {
-                let ty = self.resolve_vars_if_possible(ty);
-                if ty.references_error() || ty.is_ty_var() {
-                    debug!("resolve_type_vars_or_error: error from {:?}", ty);
-                    Err(())
-                } else {
-                    Ok(ty)
-                }
-            }
-            // FIXME
-            None if self.is_tainted_by_errors() => Err(()),
-            None => {
-                bug!(
-                    "no type for node {} in mem_categorization",
-                    self.tcx().hir().node_to_string(id)
-                );
-            }
-        }
-    }
-
-    pub(crate) fn node_ty(&self, hir_id: HirId) -> McResult<Ty<'tcx>> {
-        self.resolve_type_vars_or_error(hir_id, self.typeck_results.node_type_opt(hir_id))
-    }
-
-    fn expr_ty(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> {
-        self.resolve_type_vars_or_error(expr.hir_id, self.typeck_results.expr_ty_opt(expr))
-    }
-
-    pub(crate) fn expr_ty_adjusted(&self, expr: &hir::Expr<'_>) -> McResult<Ty<'tcx>> {
-        self.resolve_type_vars_or_error(expr.hir_id, self.typeck_results.expr_ty_adjusted_opt(expr))
-    }
-
-    /// Returns the type of value that this pattern matches against.
-    /// Some non-obvious cases:
-    ///
-    /// - a `ref x` binding matches against a value of type `T` and gives
-    ///   `x` the type `&T`; we return `T`.
-    /// - a pattern with implicit derefs (thanks to default binding
-    ///   modes #42640) may look like `Some(x)` but in fact have
-    ///   implicit deref patterns attached (e.g., it is really
-    ///   `&Some(x)`). In that case, we return the "outermost" type
-    ///   (e.g., `&Option<T>`).
-    pub(crate) fn pat_ty_adjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
-        // Check for implicit `&` types wrapping the pattern; note
-        // that these are never attached to binding patterns, so
-        // actually this is somewhat "disjoint" from the code below
-        // that aims to account for `ref x`.
-        if let Some(vec) = self.typeck_results.pat_adjustments().get(pat.hir_id) {
-            if let Some(first_ty) = vec.first() {
-                debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
-                return Ok(*first_ty);
-            }
-        }
-
-        self.pat_ty_unadjusted(pat)
-    }
-
-    /// Like `pat_ty`, but ignores implicit `&` patterns.
-    #[instrument(level = "debug", skip(self), ret)]
-    fn pat_ty_unadjusted(&self, pat: &hir::Pat<'_>) -> McResult<Ty<'tcx>> {
-        let base_ty = self.node_ty(pat.hir_id)?;
-        trace!(?base_ty);
-
-        // This code detects whether we are looking at a `ref x`,
-        // and if so, figures out what the type *being borrowed* is.
-        match pat.kind {
-            PatKind::Binding(..) => {
-                let bm = *self
-                    .typeck_results
-                    .pat_binding_modes()
-                    .get(pat.hir_id)
-                    .expect("missing binding mode");
-
-                if matches!(bm.0, hir::ByRef::Yes(_)) {
-                    // a bind-by-ref means that the base_ty will be the type of the ident itself,
-                    // but what we want here is the type of the underlying value being borrowed.
-                    // So peel off one-level, turning the &T into T.
-                    match base_ty.builtin_deref(false) {
-                        Some(t) => Ok(t.ty),
-                        None => {
-                            debug!("By-ref binding of non-derefable type");
-                            Err(())
-                        }
-                    }
-                } else {
-                    Ok(base_ty)
-                }
-            }
-            _ => Ok(base_ty),
-        }
-    }
-
-    pub(crate) fn cat_expr(&self, expr: &hir::Expr<'_>) -> McResult<PlaceWithHirId<'tcx>> {
-        // This recursion helper avoids going through *too many*
-        // adjustments, since *only* non-overloaded deref recurses.
-        fn helper<'a, 'tcx>(
-            mc: &MemCategorizationContext<'a, 'tcx>,
-            expr: &hir::Expr<'_>,
-            adjustments: &[adjustment::Adjustment<'tcx>],
-        ) -> McResult<PlaceWithHirId<'tcx>> {
-            match adjustments.split_last() {
-                None => mc.cat_expr_unadjusted(expr),
-                Some((adjustment, previous)) => {
-                    mc.cat_expr_adjusted_with(expr, || helper(mc, expr, previous), adjustment)
-                }
-            }
-        }
-
-        helper(self, expr, self.typeck_results.expr_adjustments(expr))
-    }
-
-    pub(crate) fn cat_expr_adjusted(
-        &self,
-        expr: &hir::Expr<'_>,
-        previous: PlaceWithHirId<'tcx>,
-        adjustment: &adjustment::Adjustment<'tcx>,
-    ) -> McResult<PlaceWithHirId<'tcx>> {
-        self.cat_expr_adjusted_with(expr, || Ok(previous), adjustment)
-    }
-
-    #[instrument(level = "debug", skip(self, previous))]
-    fn cat_expr_adjusted_with<F>(
-        &self,
-        expr: &hir::Expr<'_>,
-        previous: F,
-        adjustment: &adjustment::Adjustment<'tcx>,
-    ) -> McResult<PlaceWithHirId<'tcx>>
-    where
-        F: FnOnce() -> McResult<PlaceWithHirId<'tcx>>,
-    {
-        let target = self.resolve_vars_if_possible(adjustment.target);
-        match adjustment.kind {
-            adjustment::Adjust::Deref(overloaded) => {
-                // Equivalent to *expr or something similar.
-                let base = if let Some(deref) = overloaded {
-                    let ref_ty = Ty::new_ref(self.tcx(), deref.region, target, deref.mutbl);
-                    self.cat_rvalue(expr.hir_id, ref_ty)
-                } else {
-                    previous()?
-                };
-                self.cat_deref(expr, base)
-            }
-
-            adjustment::Adjust::NeverToAny
-            | adjustment::Adjust::Pointer(_)
-            | adjustment::Adjust::Borrow(_)
-            | adjustment::Adjust::DynStar => {
-                // Result is an rvalue.
-                Ok(self.cat_rvalue(expr.hir_id, target))
-            }
-        }
-    }
-
-    #[instrument(level = "debug", skip(self), ret)]
-    pub(crate) fn cat_expr_unadjusted(
-        &self,
-        expr: &hir::Expr<'_>,
-    ) -> McResult<PlaceWithHirId<'tcx>> {
-        let expr_ty = self.expr_ty(expr)?;
-        match expr.kind {
-            hir::ExprKind::Unary(hir::UnOp::Deref, e_base) => {
-                if self.typeck_results.is_method_call(expr) {
-                    self.cat_overloaded_place(expr, e_base)
-                } else {
-                    let base = self.cat_expr(e_base)?;
-                    self.cat_deref(expr, base)
-                }
-            }
-
-            hir::ExprKind::Field(base, _) => {
-                let base = self.cat_expr(base)?;
-                debug!(?base);
-
-                let field_idx = self
-                    .typeck_results
-                    .field_indices()
-                    .get(expr.hir_id)
-                    .cloned()
-                    .expect("Field index not found");
-
-                Ok(self.cat_projection(
-                    expr,
-                    base,
-                    expr_ty,
-                    ProjectionKind::Field(field_idx, FIRST_VARIANT),
-                ))
-            }
-
-            hir::ExprKind::Index(base, _, _) => {
-                if self.typeck_results.is_method_call(expr) {
-                    // If this is an index implemented by a method call, then it
-                    // will include an implicit deref of the result.
-                    // The call to index() returns a `&T` value, which
-                    // is an rvalue. That is what we will be
-                    // dereferencing.
-                    self.cat_overloaded_place(expr, base)
-                } else {
-                    let base = self.cat_expr(base)?;
-                    Ok(self.cat_projection(expr, base, expr_ty, ProjectionKind::Index))
-                }
-            }
-
-            hir::ExprKind::Path(ref qpath) => {
-                let res = self.typeck_results.qpath_res(qpath, expr.hir_id);
-                self.cat_res(expr.hir_id, expr.span, expr_ty, res)
-            }
-
-            hir::ExprKind::Type(e, _) => self.cat_expr(e),
-
-            hir::ExprKind::AddrOf(..)
-            | hir::ExprKind::Call(..)
-            | hir::ExprKind::Assign(..)
-            | hir::ExprKind::AssignOp(..)
-            | hir::ExprKind::Closure { .. }
-            | hir::ExprKind::Ret(..)
-            | hir::ExprKind::Become(..)
-            | hir::ExprKind::Unary(..)
-            | hir::ExprKind::Yield(..)
-            | hir::ExprKind::MethodCall(..)
-            | hir::ExprKind::Cast(..)
-            | hir::ExprKind::DropTemps(..)
-            | hir::ExprKind::Array(..)
-            | hir::ExprKind::If(..)
-            | hir::ExprKind::Tup(..)
-            | hir::ExprKind::Binary(..)
-            | hir::ExprKind::Block(..)
-            | hir::ExprKind::Let(..)
-            | hir::ExprKind::Loop(..)
-            | hir::ExprKind::Match(..)
-            | hir::ExprKind::Lit(..)
-            | hir::ExprKind::ConstBlock(..)
-            | hir::ExprKind::Break(..)
-            | hir::ExprKind::Continue(..)
-            | hir::ExprKind::Struct(..)
-            | hir::ExprKind::Repeat(..)
-            | hir::ExprKind::InlineAsm(..)
-            | hir::ExprKind::OffsetOf(..)
-            | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr_ty)),
-        }
-    }
-
-    #[instrument(level = "debug", skip(self, span), ret)]
-    pub(crate) fn cat_res(
-        &self,
-        hir_id: HirId,
-        span: Span,
-        expr_ty: Ty<'tcx>,
-        res: Res,
-    ) -> McResult<PlaceWithHirId<'tcx>> {
-        match res {
-            Res::Def(
-                DefKind::Ctor(..)
-                | DefKind::Const
-                | DefKind::ConstParam
-                | DefKind::AssocConst
-                | DefKind::Fn
-                | DefKind::AssocFn,
-                _,
-            )
-            | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, expr_ty)),
-
-            Res::Def(DefKind::Static { .. }, _) => {
-                Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new()))
-            }
-
-            Res::Local(var_id) => {
-                if self.upvars.is_some_and(|upvars| upvars.contains_key(&var_id)) {
-                    self.cat_upvar(hir_id, var_id)
-                } else {
-                    Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Local(var_id), Vec::new()))
-                }
-            }
-
-            def => span_bug!(span, "unexpected definition in memory categorization: {:?}", def),
-        }
-    }
-
-    /// Categorize an upvar.
-    ///
-    /// Note: the actual upvar access contains invisible derefs of closure
-    /// environment and upvar reference as appropriate. Only regionck cares
-    /// about these dereferences, so we let it compute them as needed.
-    #[instrument(level = "debug", skip(self), ret)]
-    fn cat_upvar(&self, hir_id: HirId, var_id: HirId) -> McResult<PlaceWithHirId<'tcx>> {
-        let closure_expr_def_id = self.body_owner;
-
-        let upvar_id = ty::UpvarId {
-            var_path: ty::UpvarPath { hir_id: var_id },
-            closure_expr_id: closure_expr_def_id,
-        };
-        let var_ty = self.node_ty(var_id)?;
-
-        Ok(PlaceWithHirId::new(hir_id, var_ty, PlaceBase::Upvar(upvar_id), Vec::new()))
-    }
-
-    #[instrument(level = "debug", skip(self), ret)]
-    pub(crate) fn cat_rvalue(&self, hir_id: HirId, expr_ty: Ty<'tcx>) -> PlaceWithHirId<'tcx> {
-        PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new())
-    }
-
-    #[instrument(level = "debug", skip(self, node), ret)]
-    pub(crate) fn cat_projection<N: HirNode>(
-        &self,
-        node: &N,
-        base_place: PlaceWithHirId<'tcx>,
-        ty: Ty<'tcx>,
-        kind: ProjectionKind,
-    ) -> PlaceWithHirId<'tcx> {
-        let place_ty = base_place.place.ty();
-        let mut projections = base_place.place.projections;
-
-        let node_ty = self.typeck_results.node_type(node.hir_id());
-        // Opaque types can't have field projections, but we can instead convert
-        // the current place in-place (heh) to the hidden type, and then apply all
-        // follow up projections on that.
-        if node_ty != place_ty && matches!(place_ty.kind(), ty::Alias(ty::Opaque, ..)) {
-            projections.push(Projection { kind: ProjectionKind::OpaqueCast, ty: node_ty });
-        }
-        projections.push(Projection { kind, ty });
-        PlaceWithHirId::new(
-            node.hir_id(),
-            base_place.place.base_ty,
-            base_place.place.base,
-            projections,
-        )
-    }
-
-    #[instrument(level = "debug", skip(self))]
-    fn cat_overloaded_place(
-        &self,
-        expr: &hir::Expr<'_>,
-        base: &hir::Expr<'_>,
-    ) -> McResult<PlaceWithHirId<'tcx>> {
-        // Reconstruct the output assuming it's a reference with the
-        // same region and mutability as the receiver. This holds for
-        // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
-        let place_ty = self.expr_ty(expr)?;
-        let base_ty = self.expr_ty_adjusted(base)?;
-
-        let ty::Ref(region, _, mutbl) = *base_ty.kind() else {
-            span_bug!(expr.span, "cat_overloaded_place: base is not a reference");
-        };
-        let ref_ty = Ty::new_ref(self.tcx(), region, place_ty, mutbl);
-
-        let base = self.cat_rvalue(expr.hir_id, ref_ty);
-        self.cat_deref(expr, base)
-    }
-
-    #[instrument(level = "debug", skip(self, node), ret)]
-    fn cat_deref(
-        &self,
-        node: &impl HirNode,
-        base_place: PlaceWithHirId<'tcx>,
-    ) -> McResult<PlaceWithHirId<'tcx>> {
-        let base_curr_ty = base_place.place.ty();
-        let deref_ty = match base_curr_ty.builtin_deref(true) {
-            Some(mt) => mt.ty,
-            None => {
-                debug!("explicit deref of non-derefable type: {:?}", base_curr_ty);
-                return Err(());
-            }
-        };
-        let mut projections = base_place.place.projections;
-        projections.push(Projection { kind: ProjectionKind::Deref, ty: deref_ty });
-
-        Ok(PlaceWithHirId::new(
-            node.hir_id(),
-            base_place.place.base_ty,
-            base_place.place.base,
-            projections,
-        ))
-    }
-
-    pub(crate) fn cat_pattern<F>(
-        &self,
-        place: PlaceWithHirId<'tcx>,
-        pat: &hir::Pat<'_>,
-        mut op: F,
-    ) -> McResult<()>
-    where
-        F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
-    {
-        self.cat_pattern_(place, pat, &mut op)
-    }
-
-    /// Returns the variant index for an ADT used within a Struct or TupleStruct pattern
-    /// Here `pat_hir_id` is the HirId of the pattern itself.
-    fn variant_index_for_adt(
-        &self,
-        qpath: &hir::QPath<'_>,
-        pat_hir_id: HirId,
-        span: Span,
-    ) -> McResult<VariantIdx> {
-        let res = self.typeck_results.qpath_res(qpath, pat_hir_id);
-        let ty = self.typeck_results.node_type(pat_hir_id);
-        let ty::Adt(adt_def, _) = ty.kind() else {
-            self.tcx()
-                .dcx()
-                .span_delayed_bug(span, "struct or tuple struct pattern not applied to an ADT");
-            return Err(());
-        };
-
-        match res {
-            Res::Def(DefKind::Variant, variant_id) => Ok(adt_def.variant_index_with_id(variant_id)),
-            Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
-                Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id))
-            }
-            Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
-            | Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
-            | Res::SelfCtor(..)
-            | Res::SelfTyParam { .. }
-            | Res::SelfTyAlias { .. } => {
-                // Structs and Unions have only have one variant.
-                Ok(FIRST_VARIANT)
-            }
-            _ => bug!("expected ADT path, found={:?}", res),
-        }
-    }
-
-    /// Returns the total number of fields in an ADT variant used within a pattern.
-    /// Here `pat_hir_id` is the HirId of the pattern itself.
-    fn total_fields_in_adt_variant(
-        &self,
-        pat_hir_id: HirId,
-        variant_index: VariantIdx,
-        span: Span,
-    ) -> McResult<usize> {
-        let ty = self.typeck_results.node_type(pat_hir_id);
-        match ty.kind() {
-            ty::Adt(adt_def, _) => Ok(adt_def.variant(variant_index).fields.len()),
-            _ => {
-                self.tcx()
-                    .dcx()
-                    .span_bug(span, "struct or tuple struct pattern not applied to an ADT");
-            }
-        }
-    }
-
-    /// Returns the total number of fields in a tuple used within a Tuple pattern.
-    /// Here `pat_hir_id` is the HirId of the pattern itself.
-    fn total_fields_in_tuple(&self, pat_hir_id: HirId, span: Span) -> McResult<usize> {
-        let ty = self.typeck_results.node_type(pat_hir_id);
-        match ty.kind() {
-            ty::Tuple(args) => Ok(args.len()),
-            _ => {
-                self.tcx().dcx().span_delayed_bug(span, "tuple pattern not applied to a tuple");
-                Err(())
-            }
-        }
-    }
-
-    /// Here, `place` is the `PlaceWithHirId` being matched and pat is the pattern it
-    /// is being matched against.
-    ///
-    /// In general, the way that this works is that we walk down the pattern,
-    /// constructing a `PlaceWithHirId` that represents the path that will be taken
-    /// to reach the value being matched.
-    #[instrument(skip(self, op), ret, level = "debug")]
-    fn cat_pattern_<F>(
-        &self,
-        mut place_with_id: PlaceWithHirId<'tcx>,
-        pat: &hir::Pat<'_>,
-        op: &mut F,
-    ) -> McResult<()>
-    where
-        F: FnMut(&PlaceWithHirId<'tcx>, &hir::Pat<'_>),
-    {
-        // If (pattern) adjustments are active for this pattern, adjust the `PlaceWithHirId` correspondingly.
-        // `PlaceWithHirId`s are constructed differently from patterns. For example, in
-        //
-        // ```
-        // match foo {
-        //     &&Some(x, ) => { ... },
-        //     _ => { ... },
-        // }
-        // ```
-        //
-        // the pattern `&&Some(x,)` is represented as `Ref { Ref { TupleStruct }}`. To build the
-        // corresponding `PlaceWithHirId` we start with the `PlaceWithHirId` for `foo`, and then, by traversing the
-        // pattern, try to answer the question: given the address of `foo`, how is `x` reached?
-        //
-        // `&&Some(x,)` `place_foo`
-        //  `&Some(x,)` `deref { place_foo}`
-        //   `Some(x,)` `deref { deref { place_foo }}`
-        //       `(x,)` `field0 { deref { deref { place_foo }}}` <- resulting place
-        //
-        // The above example has no adjustments. If the code were instead the (after adjustments,
-        // equivalent) version
-        //
-        // ```
-        // match foo {
-        //     Some(x, ) => { ... },
-        //     _ => { ... },
-        // }
-        // ```
-        //
-        // Then we see that to get the same result, we must start with
-        // `deref { deref { place_foo }}` instead of `place_foo` since the pattern is now `Some(x,)`
-        // and not `&&Some(x,)`, even though its assigned type is that of `&&Some(x,)`.
-        for _ in 0..self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(0, |v| v.len()) {
-            debug!("applying adjustment to place_with_id={:?}", place_with_id);
-            place_with_id = self.cat_deref(pat, place_with_id)?;
-        }
-        let place_with_id = place_with_id; // lose mutability
-        debug!("applied adjustment derefs to get place_with_id={:?}", place_with_id);
-
-        // Invoke the callback, but only now, after the `place_with_id` has adjusted.
-        //
-        // To see that this makes sense, consider `match &Some(3) { Some(x) => { ... }}`. In that
-        // case, the initial `place_with_id` will be that for `&Some(3)` and the pattern is `Some(x)`. We
-        // don't want to call `op` with these incompatible values. As written, what happens instead
-        // is that `op` is called with the adjusted place (that for `*&Some(3)`) and the pattern
-        // `Some(x)` (which matches). Recursing once more, `*&Some(3)` and the pattern `Some(x)`
-        // result in the place `Downcast<Some>(*&Some(3)).0` associated to `x` and invoke `op` with
-        // that (where the `ref` on `x` is implied).
-        op(&place_with_id, pat);
-
-        match pat.kind {
-            PatKind::Tuple(subpats, dots_pos) => {
-                // (p1, ..., pN)
-                let total_fields = self.total_fields_in_tuple(pat.hir_id, pat.span)?;
-
-                for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
-                    let subpat_ty = self.pat_ty_adjusted(subpat)?;
-                    let projection_kind =
-                        ProjectionKind::Field(FieldIdx::from_usize(i), FIRST_VARIANT);
-                    let sub_place =
-                        self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind);
-                    self.cat_pattern_(sub_place, subpat, op)?;
-                }
-            }
-
-            PatKind::TupleStruct(ref qpath, subpats, dots_pos) => {
-                // S(p1, ..., pN)
-                let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
-                let total_fields =
-                    self.total_fields_in_adt_variant(pat.hir_id, variant_index, pat.span)?;
-
-                for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
-                    let subpat_ty = self.pat_ty_adjusted(subpat)?;
-                    let projection_kind =
-                        ProjectionKind::Field(FieldIdx::from_usize(i), variant_index);
-                    let sub_place =
-                        self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind);
-                    self.cat_pattern_(sub_place, subpat, op)?;
-                }
-            }
-
-            PatKind::Struct(ref qpath, field_pats, _) => {
-                // S { f1: p1, ..., fN: pN }
-
-                let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
-
-                for fp in field_pats {
-                    let field_ty = self.pat_ty_adjusted(fp.pat)?;
-                    let field_index = self
-                        .typeck_results
-                        .field_indices()
-                        .get(fp.hir_id)
-                        .cloned()
-                        .expect("no index for a field");
-
-                    let field_place = self.cat_projection(
-                        pat,
-                        place_with_id.clone(),
-                        field_ty,
-                        ProjectionKind::Field(field_index, variant_index),
-                    );
-                    self.cat_pattern_(field_place, fp.pat, op)?;
-                }
-            }
-
-            PatKind::Or(pats) => {
-                for pat in pats {
-                    self.cat_pattern_(place_with_id.clone(), pat, op)?;
-                }
-            }
-
-            PatKind::Binding(.., Some(subpat)) => {
-                self.cat_pattern_(place_with_id, subpat, op)?;
-            }
-
-            PatKind::Box(subpat) | PatKind::Ref(subpat, _) => {
-                // box p1, &p1, &mut p1. we can ignore the mutability of
-                // PatKind::Ref since that information is already contained
-                // in the type.
-                let subplace = self.cat_deref(pat, place_with_id)?;
-                self.cat_pattern_(subplace, subpat, op)?;
-            }
-            PatKind::Deref(subpat) => {
-                let mutable = self.typeck_results.pat_has_ref_mut_binding(subpat);
-                let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
-                let re_erased = self.tcx().lifetimes.re_erased;
-                let ty = self.pat_ty_adjusted(subpat)?;
-                let ty = Ty::new_ref(self.tcx(), re_erased, ty, mutability);
-                // A deref pattern generates a temporary.
-                let place = self.cat_rvalue(pat.hir_id, ty);
-                self.cat_pattern_(place, subpat, op)?;
-            }
-
-            PatKind::Slice(before, ref slice, after) => {
-                let Some(element_ty) = place_with_id.place.ty().builtin_index() else {
-                    debug!("explicit index of non-indexable type {:?}", place_with_id);
-                    return Err(());
-                };
-                let elt_place = self.cat_projection(
-                    pat,
-                    place_with_id.clone(),
-                    element_ty,
-                    ProjectionKind::Index,
-                );
-                for before_pat in before {
-                    self.cat_pattern_(elt_place.clone(), before_pat, op)?;
-                }
-                if let Some(slice_pat) = *slice {
-                    let slice_pat_ty = self.pat_ty_adjusted(slice_pat)?;
-                    let slice_place = self.cat_projection(
-                        pat,
-                        place_with_id,
-                        slice_pat_ty,
-                        ProjectionKind::Subslice,
-                    );
-                    self.cat_pattern_(slice_place, slice_pat, op)?;
-                }
-                for after_pat in after {
-                    self.cat_pattern_(elt_place.clone(), after_pat, op)?;
-                }
-            }
-
-            PatKind::Path(_)
-            | PatKind::Binding(.., None)
-            | PatKind::Lit(..)
-            | PatKind::Range(..)
-            | PatKind::Never
-            | PatKind::Wild
-            | PatKind::Err(_) => {
-                // always ok
-            }
-        }
-
-        Ok(())
-    }
-}
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index d570152..9c64f94 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -16,6 +16,7 @@
 use rustc_middle::ty::{
     self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, UserArgs, UserType,
 };
+use rustc_middle::{bug, span_bug};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_trait_selection::traits;
 
@@ -450,7 +451,7 @@
         // `foo.bar::<u32>(...)` -- the `Self` type here will be the
         // type of `foo` (possibly adjusted), but we don't want to
         // include that. We want just the `[_, u32]` part.
-        if !args.is_empty() && !generics.params.is_empty() {
+        if !args.is_empty() && !generics.is_own_empty() {
             let user_type_annotation = self.probe(|_| {
                 let user_args = UserArgs {
                     args: GenericArgs::for_item(self.tcx, pick.item.def_id, |param, _| {
@@ -564,16 +565,12 @@
         // `self.add_required_obligations(self.span, def_id, &all_args);`
         for obligation in traits::predicates_for_generics(
             |idx, span| {
-                let code = if span.is_dummy() {
-                    ObligationCauseCode::ExprItemObligation(def_id, self.call_expr.hir_id, idx)
-                } else {
-                    ObligationCauseCode::ExprBindingObligation(
-                        def_id,
-                        span,
-                        self.call_expr.hir_id,
-                        idx,
-                    )
-                };
+                let code = ObligationCauseCode::WhereClauseInExpr(
+                    def_id,
+                    span,
+                    self.call_expr.hir_id,
+                    idx,
+                );
                 traits::ObligationCause::new(self.span, self.body_id, code)
             },
             self.param_env,
@@ -589,7 +586,7 @@
         // the function type must also be well-formed (this is not
         // implied by the args being well-formed because of inherent
         // impls and late-bound regions - see issue #28609).
-        self.register_wf_obligation(fty.into(), self.span, traits::WellFormed(None));
+        self.register_wf_obligation(fty.into(), self.span, ObligationCauseCode::WellFormed(None));
     }
 
     ///////////////////////////////////////////////////////////////////////////
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 39d54f1..4165ccb 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -3,7 +3,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/method-lookup.html
 
 mod confirm;
-mod prelude2021;
+mod prelude_edition_lints;
 pub mod probe;
 mod suggest;
 
@@ -20,6 +20,7 @@
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitableExt};
 use rustc_middle::ty::{GenericArgs, GenericArgsRef};
+use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -90,7 +91,7 @@
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Determines whether the type `self_ty` supports a visible method named `method_name` or not.
     #[instrument(level = "debug", skip(self))]
-    pub fn method_exists(
+    pub fn method_exists_for_diagnostic(
         &self,
         method_name: Ident,
         self_ty: Ty<'tcx>,
@@ -101,7 +102,7 @@
             probe::Mode::MethodCall,
             method_name,
             return_type,
-            IsSuggestion(false),
+            IsSuggestion(true),
             self_ty,
             call_expr_id,
             ProbeScope::TraitsInScope,
@@ -185,7 +186,9 @@
         let pick =
             self.lookup_probe(segment.ident, self_ty, call_expr, ProbeScope::TraitsInScope)?;
 
-        self.lint_dot_call_from_2018(self_ty, segment, span, call_expr, self_expr, &pick, args);
+        self.lint_edition_dependent_dot_call(
+            self_ty, segment, span, call_expr, self_expr, &pick, args,
+        );
 
         for &import_id in &pick.import_ids {
             debug!("used_trait_import: {:?}", import_id);
@@ -315,7 +318,7 @@
         trait_def_id: DefId,
         self_ty: Ty<'tcx>,
         opt_input_types: Option<&[Ty<'tcx>]>,
-    ) -> (traits::PredicateObligation<'tcx>, &'tcx ty::List<ty::GenericArg<'tcx>>) {
+    ) -> (traits::PredicateObligation<'tcx>, ty::GenericArgsRef<'tcx>) {
         // Construct a trait-reference `self_ty : Trait<input_tys>`
         let args = GenericArgs::for_item(self.tcx, trait_def_id, |param, _| {
             match param.kind {
@@ -365,7 +368,7 @@
         m_name: Ident,
         trait_def_id: DefId,
         obligation: traits::PredicateObligation<'tcx>,
-        args: &'tcx ty::List<ty::GenericArg<'tcx>>,
+        args: ty::GenericArgsRef<'tcx>,
     ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
         debug!(?obligation);
 
diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
similarity index 84%
rename from compiler/rustc_hir_typeck/src/method/prelude2021.rs
rename to compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
index 22eef8e..e9eab69 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude_edition_lints.rs
@@ -1,13 +1,13 @@
-use crate::{
-    method::probe::{self, Pick},
-    FnCtxt,
-};
+use crate::method::probe::{self, Pick};
+use crate::FnCtxt;
+
 use hir::def_id::DefId;
 use hir::HirId;
 use hir::ItemKind;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
+use rustc_lint::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
+use rustc_middle::span_bug;
 use rustc_middle::ty::{self, Ty};
 use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS;
 use rustc_span::symbol::kw::{Empty, Underscore};
@@ -17,7 +17,7 @@
 use std::fmt::Write;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
-    pub(super) fn lint_dot_call_from_2018(
+    pub(super) fn lint_edition_dependent_dot_call(
         &self,
         self_ty: Ty<'tcx>,
         segment: &hir::PathSegment<'_>,
@@ -32,22 +32,32 @@
             segment.ident, self_ty, call_expr, self_expr
         );
 
-        // Rust 2021 and later is already using the new prelude
-        if span.at_least_rust_2021() {
-            return;
-        }
-
-        let prelude_or_array_lint = match segment.ident.name {
+        let (prelude_or_array_lint, edition) = match segment.ident.name {
             // `try_into` was added to the prelude in Rust 2021.
-            sym::try_into => RUST_2021_PRELUDE_COLLISIONS,
+            sym::try_into if !span.at_least_rust_2021() => (RUST_2021_PRELUDE_COLLISIONS, "2021"),
             // `into_iter` wasn't added to the prelude,
             // but `[T; N].into_iter()` doesn't resolve to IntoIterator::into_iter
             // before Rust 2021, which results in the same problem.
             // It is only a problem for arrays.
-            sym::into_iter if let ty::Array(..) = self_ty.kind() => {
-                // In this case, it wasn't really a prelude addition that was the problem.
-                // Instead, the problem is that the array-into_iter hack will no longer apply in Rust 2021.
-                rustc_lint::ARRAY_INTO_ITER
+            sym::into_iter => {
+                if let ty::Array(..) = self_ty.kind()
+                    && !span.at_least_rust_2021()
+                {
+                    // In this case, it wasn't really a prelude addition that was the problem.
+                    // Instead, the problem is that the array-into_iter hack will no longer
+                    // apply in Rust 2021.
+                    (ARRAY_INTO_ITER, "2021")
+                } else if self_ty.is_box()
+                    && self_ty.boxed_ty().is_slice()
+                    && !span.at_least_rust_2024()
+                {
+                    // In this case, it wasn't really a prelude addition that was the problem.
+                    // Instead, the problem is that the boxed-slice-into_iter hack will no
+                    // longer apply in Rust 2024.
+                    (BOXED_SLICE_INTO_ITER, "2024")
+                } else {
+                    return;
+                }
             }
             _ => return,
         };
@@ -81,7 +91,10 @@
                 prelude_or_array_lint,
                 self_expr.hir_id,
                 self_expr.span,
-                format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
+                format!(
+                    "trait method `{}` will become ambiguous in Rust {edition}",
+                    segment.ident.name
+                ),
                 |lint| {
                     let sp = self_expr.span;
 
@@ -131,7 +144,10 @@
                 prelude_or_array_lint,
                 call_expr.hir_id,
                 call_expr.span,
-                format!("trait method `{}` will become ambiguous in Rust 2021", segment.ident.name),
+                format!(
+                    "trait method `{}` will become ambiguous in Rust {edition}",
+                    segment.ident.name
+                ),
                 |lint| {
                     let sp = call_expr.span;
                     let trait_name = self.trait_path_or_bare_name(
@@ -218,8 +234,7 @@
         // If we know it does not, we don't need to warn.
         if method_name.name == sym::from_iter {
             if let Some(trait_def_id) = self.tcx.get_diagnostic_item(sym::FromIterator) {
-                let any_type =
-                    self.infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span });
+                let any_type = self.infcx.next_ty_var(span);
                 if !self
                     .infcx
                     .type_implements_trait(trait_def_id, [self_ty, any_type], self.param_env)
@@ -251,23 +266,23 @@
                 let trait_path = self.trait_path_or_bare_name(span, expr_id, container_id);
                 let trait_generics = self.tcx.generics_of(container_id);
 
-                let trait_name = if trait_generics.params.len() <= trait_generics.has_self as usize
-                {
-                    trait_path
-                } else {
-                    let counts = trait_generics.own_counts();
-                    format!(
-                        "{}<{}>",
-                        trait_path,
-                        std::iter::repeat("'_")
-                            .take(counts.lifetimes)
-                            .chain(std::iter::repeat("_").take(
-                                counts.types + counts.consts - trait_generics.has_self as usize
-                            ))
-                            .collect::<Vec<_>>()
-                            .join(", ")
-                    )
-                };
+                let trait_name =
+                    if trait_generics.own_params.len() <= trait_generics.has_self as usize {
+                        trait_path
+                    } else {
+                        let counts = trait_generics.own_counts();
+                        format!(
+                            "{}<{}>",
+                            trait_path,
+                            std::iter::repeat("'_")
+                                .take(counts.lifetimes)
+                                .chain(std::iter::repeat("_").take(
+                                    counts.types + counts.consts - trait_generics.has_self as usize
+                                ))
+                                .collect::<Vec<_>>()
+                                .join(", ")
+                        )
+                    };
 
                 let mut self_ty_name = self_ty_span
                     .find_ancestor_inside(span)
@@ -280,7 +295,7 @@
                 if !self_ty_name.contains('<') {
                     if let ty::Adt(def, _) = self_ty.kind() {
                         let generics = self.tcx.generics_of(def.did());
-                        if !generics.params.is_empty() {
+                        if !generics.is_own_empty() {
                             let counts = generics.own_counts();
                             self_ty_name += &format!(
                                 "<{}>",
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 8a7ebd6..e0a6033 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -15,14 +15,16 @@
 use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
+use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::middle::stability;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
 use rustc_middle::ty::AssocItem;
 use rustc_middle::ty::GenericParamDefKind;
-use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::Upcast;
 use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{GenericArgs, GenericArgsRef};
+use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::def_id::DefId;
 use rustc_span::def_id::LocalDefId;
@@ -88,6 +90,11 @@
     >,
 
     scope_expr_id: HirId,
+
+    /// Is this probe being done for a diagnostic? This will skip some error reporting
+    /// machinery, since we don't particularly care about, for example, similarly named
+    /// candidates if we're *reporting* similarly named candidates.
+    is_suggestion: IsSuggestion,
 }
 
 impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> {
@@ -218,7 +225,7 @@
     /// would use to decide if a method is a plausible fit for
     /// ambiguity purposes).
     #[instrument(level = "debug", skip(self, candidate_filter))]
-    pub fn probe_for_return_type(
+    pub fn probe_for_return_type_for_diagnostic(
         &self,
         span: Span,
         mode: Mode,
@@ -457,6 +464,7 @@
                 &orig_values,
                 steps.steps,
                 scope_expr_id,
+                is_suggestion,
             );
 
             probe_cx.assemble_inherent_candidates();
@@ -551,6 +559,7 @@
         orig_steps_var_values: &'a OriginalQueryValues<'tcx>,
         steps: &'tcx [CandidateStep<'tcx>],
         scope_expr_id: HirId,
+        is_suggestion: IsSuggestion,
     ) -> ProbeContext<'a, 'tcx> {
         ProbeContext {
             fcx,
@@ -568,6 +577,7 @@
             static_candidates: RefCell::new(Vec::new()),
             unsatisfied_predicates: RefCell::new(Vec::new()),
             scope_expr_id,
+            is_suggestion,
         }
     }
 
@@ -942,6 +952,18 @@
             return r;
         }
 
+        // If it's a `lookup_probe_for_diagnostic`, then quit early. No need to
+        // probe for other candidates.
+        if self.is_suggestion.0 {
+            return Err(MethodError::NoMatch(NoMatchData {
+                static_candidates: vec![],
+                unsatisfied_predicates: vec![],
+                out_of_scope_traits: vec![],
+                similar_candidate: None,
+                mode: self.mode,
+            }));
+        }
+
         debug!("pick: actual search failed, assemble diagnostics");
 
         let static_candidates = std::mem::take(self.static_candidates.get_mut());
@@ -1400,16 +1422,12 @@
                     // Convert the bounds into obligations.
                     ocx.register_obligations(traits::predicates_for_generics(
                         |idx, span| {
-                            let code = if span.is_dummy() {
-                                traits::ExprItemObligation(impl_def_id, self.scope_expr_id, idx)
-                            } else {
-                                traits::ExprBindingObligation(
-                                    impl_def_id,
-                                    span,
-                                    self.scope_expr_id,
-                                    idx,
-                                )
-                            };
+                            let code = ObligationCauseCode::WhereClauseInExpr(
+                                impl_def_id,
+                                span,
+                                self.scope_expr_id,
+                                idx,
+                            );
                             ObligationCause::new(self.span, self.body_id, code)
                         },
                         self.param_env,
@@ -1426,6 +1444,18 @@
                                 return ProbeResult::NoMatch;
                             }
                         }
+
+                        // Some trait methods are excluded for boxed slices before 2024.
+                        // (`boxed_slice.into_iter()` wants a slice iterator for compatibility.)
+                        if self_ty.is_box()
+                            && self_ty.boxed_ty().is_slice()
+                            && !method_name.span.at_least_rust_2024()
+                        {
+                            let trait_def = self.tcx.trait_def(poly_trait_ref.def_id());
+                            if trait_def.skip_boxed_slice_during_method_dispatch {
+                                return ProbeResult::NoMatch;
+                            }
+                        }
                     }
 
                     let trait_ref = self.instantiate_binder_with_fresh_vars(
@@ -1478,7 +1508,7 @@
                         }
                     }
 
-                    trait_predicate = Some(ty::Binder::dummy(trait_ref).to_predicate(self.tcx));
+                    trait_predicate = Some(trait_ref.upcast(self.tcx));
                 }
                 ObjectCandidate(poly_trait_ref) | WhereClauseCandidate(poly_trait_ref) => {
                     let trait_ref = self.instantiate_binder_with_fresh_vars(
@@ -1633,6 +1663,7 @@
                 self.orig_steps_var_values,
                 self.steps,
                 self.scope_expr_id,
+                IsSuggestion(true),
             );
             pcx.allow_similar_names = true;
             pcx.assemble_inherent_candidates();
@@ -1735,7 +1766,7 @@
         let generics = self.tcx.generics_of(method);
         assert_eq!(args.len(), generics.parent_count);
 
-        let xform_fn_sig = if generics.params.is_empty() {
+        let xform_fn_sig = if generics.is_own_empty() {
             fn_sig.instantiate(self.tcx, args)
         } else {
             let args = GenericArgs::for_item(self.tcx, method, |param, _| {
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 0780095..54af835 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -7,6 +7,7 @@
 use crate::Expectation;
 use crate::FnCtxt;
 use core::ops::ControlFlow;
+use hir::Expr;
 use rustc_ast::ast::Mutability;
 use rustc_attr::parse_confusables;
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@@ -19,14 +20,15 @@
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
-use rustc_hir::PatKind::Binding;
 use rustc_hir::PathSegment;
 use rustc_hir::{ExprKind, Node, QPath};
-use rustc_infer::infer::{self, type_variable::TypeVariableOrigin, RegionVariableOrigin};
-use rustc_middle::infer::unify_key::ConstVariableOrigin;
+use rustc_infer::infer::{self, RegionVariableOrigin};
+use rustc_middle::bug;
 use rustc_middle::ty::fast_reject::DeepRejectCtxt;
 use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
-use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
+use rustc_middle::ty::print::{
+    with_crate_prefix, with_forced_trimmed_paths, PrintTraitRefExt as _,
+};
 use rustc_middle::ty::IsSuggestable;
 use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::def_id::DefIdSet;
@@ -44,8 +46,7 @@
 
 use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
 use super::{CandidateSource, MethodError, NoMatchData};
-use rustc_hir::intravisit::Visitor;
-use std::iter;
+use rustc_hir::intravisit::{self, Visitor};
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool {
@@ -75,11 +76,8 @@
                 self.autoderef(span, ty).any(|(ty, _)| {
                     info!("check deref {:?} impl FnOnce", ty);
                     self.probe(|_| {
-                        let trait_ref = ty::TraitRef::new(
-                            tcx,
-                            fn_once,
-                            [ty, self.next_ty_var(TypeVariableOrigin { param_def_id: None, span })],
-                        );
+                        let trait_ref =
+                            ty::TraitRef::new(tcx, fn_once, [ty, self.next_ty_var(span)]);
                         let poly_trait_ref = ty::Binder::dummy(trait_ref);
                         let obligation = Obligation::misc(
                             tcx,
@@ -150,7 +148,7 @@
             return false;
         };
         let trait_ref = ty::TraitRef::new(self.tcx, into_iterator_trait, [ty]);
-        let cause = ObligationCause::new(span, self.body_id, ObligationCauseCode::MiscObligation);
+        let cause = ObligationCause::new(span, self.body_id, ObligationCauseCode::Misc);
         let obligation = Obligation::new(self.tcx, cause, self.param_env, trait_ref);
         if !self.predicate_must_hold_modulo_regions(&obligation) {
             return false;
@@ -174,7 +172,7 @@
                     }
                 }
             }
-            ty::Slice(..) | ty::Adt(..) | ty::Alias(ty::AliasKind::Opaque, _) => {
+            ty::Slice(..) | ty::Adt(..) | ty::Alias(ty::Opaque, _) => {
                 for unsatisfied in unsatisfied_predicates.iter() {
                     if is_iterator_predicate(unsatisfied.0, self.tcx) {
                         return true;
@@ -190,6 +188,7 @@
     pub fn report_method_error(
         &self,
         span: Span,
+        rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
         rcvr_ty: Ty<'tcx>,
         item_name: Ident,
         source: SelfSource<'tcx>,
@@ -214,6 +213,7 @@
             MethodError::NoMatch(mut no_match_data) => {
                 return self.report_no_match_method_error(
                     span,
+                    rcvr_opt,
                     rcvr_ty,
                     item_name,
                     source,
@@ -358,9 +358,197 @@
         err
     }
 
+    pub fn suggest_use_shadowed_binding_with_method(
+        &self,
+        rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
+        method_name: Ident,
+        ty_str_reported: &str,
+        err: &mut Diag<'_>,
+    ) {
+        #[derive(Debug)]
+        struct LetStmt {
+            ty_hir_id_opt: Option<hir::HirId>,
+            binding_id: hir::HirId,
+            span: Span,
+            init_hir_id: hir::HirId,
+        }
+
+        // Used for finding suggest binding.
+        // ```rust
+        // earlier binding for suggesting:
+        // let y = vec![1, 2];
+        // now binding:
+        // if let Some(y) = x {
+        //     y.push(y);
+        // }
+        // ```
+        struct LetVisitor<'a, 'tcx> {
+            // Error binding which don't have `method_name`.
+            binding_name: Symbol,
+            binding_id: hir::HirId,
+            // Used for check if the suggest binding has `method_name`.
+            fcx: &'a FnCtxt<'a, 'tcx>,
+            call_expr: &'tcx Expr<'tcx>,
+            method_name: Ident,
+            // Suggest the binding which is shallowed.
+            sugg_let: Option<LetStmt>,
+        }
+
+        impl<'a, 'tcx> LetVisitor<'a, 'tcx> {
+            // Check scope of binding.
+            fn is_sub_scope(&self, sub_id: hir::ItemLocalId, super_id: hir::ItemLocalId) -> bool {
+                let scope_tree = self.fcx.tcx.region_scope_tree(self.fcx.body_id);
+                if let Some(sub_var_scope) = scope_tree.var_scope(sub_id)
+                    && let Some(super_var_scope) = scope_tree.var_scope(super_id)
+                    && scope_tree.is_subscope_of(sub_var_scope, super_var_scope)
+                {
+                    return true;
+                }
+                false
+            }
+
+            // Check if an earlier shadowed binding make `the receiver` of a MethodCall has the method.
+            // If it does, record the earlier binding for subsequent notes.
+            fn check_and_add_sugg_binding(&mut self, binding: LetStmt) -> bool {
+                if !self.is_sub_scope(self.binding_id.local_id, binding.binding_id.local_id) {
+                    return false;
+                }
+
+                // Get the earlier shadowed binding'ty and use it to check the method.
+                if let Some(ty_hir_id) = binding.ty_hir_id_opt
+                    && let Some(tyck_ty) = self.fcx.node_ty_opt(ty_hir_id)
+                {
+                    if self
+                        .fcx
+                        .lookup_probe_for_diagnostic(
+                            self.method_name,
+                            tyck_ty,
+                            self.call_expr,
+                            ProbeScope::TraitsInScope,
+                            None,
+                        )
+                        .is_ok()
+                    {
+                        self.sugg_let = Some(binding);
+                        return true;
+                    } else {
+                        return false;
+                    }
+                }
+
+                // If the shadowed binding has an an itializer expression,
+                // use the initializer expression'ty to try to find the method again.
+                // For example like:  `let mut x = Vec::new();`,
+                // `Vec::new()` is the itializer expression.
+                if let Some(self_ty) = self.fcx.node_ty_opt(binding.init_hir_id)
+                    && self
+                        .fcx
+                        .lookup_probe_for_diagnostic(
+                            self.method_name,
+                            self_ty,
+                            self.call_expr,
+                            ProbeScope::TraitsInScope,
+                            None,
+                        )
+                        .is_ok()
+                {
+                    self.sugg_let = Some(binding);
+                    return true;
+                }
+                return false;
+            }
+        }
+
+        impl<'v> Visitor<'v> for LetVisitor<'_, '_> {
+            type Result = ControlFlow<()>;
+            fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
+                if let hir::StmtKind::Let(&hir::LetStmt { pat, ty, init, .. }) = ex.kind
+                    && let hir::PatKind::Binding(_, binding_id, binding_name, ..) = pat.kind
+                    && let Some(init) = init
+                    && binding_name.name == self.binding_name
+                    && binding_id != self.binding_id
+                {
+                    if self.check_and_add_sugg_binding(LetStmt {
+                        ty_hir_id_opt: if let Some(ty) = ty { Some(ty.hir_id) } else { None },
+                        binding_id: binding_id,
+                        span: pat.span,
+                        init_hir_id: init.hir_id,
+                    }) {
+                        return ControlFlow::Break(());
+                    }
+                    ControlFlow::Continue(())
+                } else {
+                    hir::intravisit::walk_stmt(self, ex)
+                }
+            }
+
+            // Used for find the error binding.
+            // When the visitor reaches this point, all the shadowed bindings
+            // have been found, so the visitor ends.
+            fn visit_pat(&mut self, p: &'v hir::Pat<'v>) -> Self::Result {
+                match p.kind {
+                    hir::PatKind::Binding(_, binding_id, binding_name, _) => {
+                        if binding_name.name == self.binding_name && binding_id == self.binding_id {
+                            return ControlFlow::Break(());
+                        }
+                    }
+                    _ => {
+                        intravisit::walk_pat(self, p);
+                    }
+                }
+                ControlFlow::Continue(())
+            }
+        }
+
+        if let Some(rcvr) = rcvr_opt
+            && let hir::ExprKind::Path(QPath::Resolved(_, path)) = rcvr.kind
+            && let hir::def::Res::Local(recv_id) = path.res
+            && let Some(segment) = path.segments.first()
+        {
+            let map = self.infcx.tcx.hir();
+            let body_id = self.tcx.hir().body_owned_by(self.body_id);
+            let body = map.body(body_id);
+
+            if let Node::Expr(call_expr) = self.tcx.parent_hir_node(rcvr.hir_id) {
+                let mut let_visitor = LetVisitor {
+                    fcx: self,
+                    call_expr,
+                    binding_name: segment.ident.name,
+                    binding_id: recv_id,
+                    method_name,
+                    sugg_let: None,
+                };
+                let_visitor.visit_body(body);
+                if let Some(sugg_let) = let_visitor.sugg_let
+                    && let Some(self_ty) = self.node_ty_opt(sugg_let.init_hir_id)
+                {
+                    let _sm = self.infcx.tcx.sess.source_map();
+                    let rcvr_name = segment.ident.name;
+                    let mut span = MultiSpan::from_span(sugg_let.span);
+                    span.push_span_label(sugg_let.span,
+                            format!("`{rcvr_name}` of type `{self_ty}` that has method `{method_name}` defined earlier here"));
+                    span.push_span_label(
+                        self.tcx.hir().span(recv_id),
+                        format!(
+                            "earlier `{rcvr_name}` shadowed here with type `{ty_str_reported}`"
+                        ),
+                    );
+                    err.span_note(
+                        span,
+                        format!(
+                            "there's an earlier shadowed binding `{rcvr_name}` of type `{self_ty}` \
+                                    that has method `{method_name}` available"
+                        ),
+                    );
+                }
+            }
+        }
+    }
+
     pub fn report_no_match_method_error(
         &self,
         mut span: Span,
+        rcvr_opt: Option<&'tcx hir::Expr<'tcx>>,
         rcvr_ty: Ty<'tcx>,
         item_name: Ident,
         source: SelfSource<'tcx>,
@@ -453,7 +641,7 @@
         let mut err = if is_write && let SelfSource::MethodCall(rcvr_expr) = source {
             self.suggest_missing_writer(rcvr_ty, rcvr_expr)
         } else {
-            tcx.dcx().create_err(NoAssociatedItem {
+            let mut err = tcx.dcx().create_err(NoAssociatedItem {
                 span,
                 item_kind,
                 item_name,
@@ -463,9 +651,20 @@
                 } else {
                     rcvr_ty.prefix_string(self.tcx)
                 },
-                ty_str: ty_str_reported,
+                ty_str: ty_str_reported.clone(),
                 trait_missing_method,
-            })
+            });
+
+            if is_method {
+                self.suggest_use_shadowed_binding_with_method(
+                    rcvr_opt,
+                    item_name,
+                    &ty_str_reported,
+                    &mut err,
+                );
+            }
+
+            err
         };
         if tcx.sess.source_map().is_multiline(sugg_span) {
             err.span_label(sugg_span.with_hi(span.lo()), "");
@@ -789,26 +988,20 @@
                     ty::PredicateKind::Clause(ty::ClauseKind::Projection(pred)) => {
                         let pred = bound_predicate.rebind(pred);
                         // `<Foo as Iterator>::Item = String`.
-                        let projection_ty = pred.skip_binder().projection_ty;
-
-                        let args_with_infer_self = tcx.mk_args_from_iter(
-                            iter::once(Ty::new_var(tcx, ty::TyVid::ZERO).into())
-                                .chain(projection_ty.args.iter().skip(1)),
-                        );
-
-                        let quiet_projection_ty =
-                            ty::AliasTy::new(tcx, projection_ty.def_id, args_with_infer_self);
+                        let projection_term = pred.skip_binder().projection_term;
+                        let quiet_projection_term =
+                            projection_term.with_self_ty(tcx, Ty::new_var(tcx, ty::TyVid::ZERO));
 
                         let term = pred.skip_binder().term;
 
-                        let obligation = format!("{projection_ty} = {term}");
+                        let obligation = format!("{projection_term} = {term}");
                         let quiet = with_forced_trimmed_paths!(format!(
                             "{} = {}",
-                            quiet_projection_ty, term
+                            quiet_projection_term, term
                         ));
 
-                        bound_span_label(projection_ty.self_ty(), &obligation, &quiet);
-                        Some((obligation, projection_ty.self_ty()))
+                        bound_span_label(projection_term.self_ty(), &obligation, &quiet);
+                        Some((obligation, projection_term.self_ty()))
                     }
                     ty::PredicateKind::Clause(ty::ClauseKind::Trait(poly_trait_ref)) => {
                         let p = poly_trait_ref.trait_ref;
@@ -830,13 +1023,13 @@
                 // Extract the predicate span and parent def id of the cause,
                 // if we have one.
                 let (item_def_id, cause_span) = match cause.as_ref().map(|cause| cause.code()) {
-                    Some(ObligationCauseCode::ImplDerivedObligation(data)) => {
+                    Some(ObligationCauseCode::ImplDerived(data)) => {
                         (data.impl_or_alias_def_id, data.span)
                     }
                     Some(
-                        ObligationCauseCode::ExprBindingObligation(def_id, span, _, _)
-                        | ObligationCauseCode::BindingObligation(def_id, span),
-                    ) => (*def_id, *span),
+                        ObligationCauseCode::WhereClauseInExpr(def_id, span, _, _)
+                        | ObligationCauseCode::WhereClause(def_id, span),
+                    ) if !span.is_dummy() => (*def_id, *span),
                     _ => continue,
                 };
 
@@ -1151,7 +1344,9 @@
             }
         }
 
-        let label_span_not_found = |err: &mut Diag<'_>| {
+        let mut find_candidate_for_method = false;
+
+        let mut label_span_not_found = |err: &mut Diag<'_>| {
             if unsatisfied_predicates.is_empty() {
                 err.span_label(span, format!("{item_kind} not found in `{ty_str}`"));
                 let is_string_or_ref_str = match rcvr_ty.kind() {
@@ -1227,6 +1422,7 @@
                         err.note(format!(
                             "the {item_kind} was found for\n{type_candidates}{additional_types}"
                         ));
+                        find_candidate_for_method = mode == Mode::MethodCall;
                     }
                 }
             } else {
@@ -1259,12 +1455,7 @@
             args.map(|args| {
                 args.iter()
                     .map(|expr| {
-                        self.node_ty_opt(expr.hir_id).unwrap_or_else(|| {
-                            self.next_ty_var(TypeVariableOrigin {
-                                param_def_id: None,
-                                span: expr.span,
-                            })
-                        })
+                        self.node_ty_opt(expr.hir_id).unwrap_or_else(|| self.next_ty_var(expr.span))
                     })
                     .collect()
             }),
@@ -1384,9 +1575,32 @@
                 );
             }
         }
-        // If an appropriate error source is not found, check method chain for possible candiates
-        if unsatisfied_predicates.is_empty()
-            && let Mode::MethodCall = mode
+
+        if !find_candidate_for_method {
+            self.lookup_segments_chain_for_no_match_method(
+                &mut err,
+                item_name,
+                item_kind,
+                source,
+                no_match_data,
+            );
+        }
+
+        self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
+        Some(err)
+    }
+
+    /// If an appropriate error source is not found, check method chain for possible candidates
+    fn lookup_segments_chain_for_no_match_method(
+        &self,
+        err: &mut Diag<'_>,
+        item_name: Ident,
+        item_kind: &str,
+        source: SelfSource<'tcx>,
+        no_match_data: &NoMatchData<'tcx>,
+    ) {
+        if no_match_data.unsatisfied_predicates.is_empty()
+            && let Mode::MethodCall = no_match_data.mode
             && let SelfSource::MethodCall(mut source_expr) = source
         {
             let mut stack_methods = vec![];
@@ -1407,6 +1621,9 @@
                         .unwrap_or(Ty::new_misc_error(self.tcx)),
                 );
 
+                // FIXME: `probe_for_name_many` searches for methods in inherent implementations,
+                // so it may return a candidate that doesn't belong to this `revr_ty`. We need to
+                // check whether the instantiated type matches the received one.
                 for _matched_method in self.probe_for_name_many(
                     Mode::MethodCall,
                     item_name,
@@ -1429,8 +1646,6 @@
                 );
             }
         }
-        self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
-        Some(err)
     }
 
     fn find_likely_intended_associated_item(
@@ -1846,18 +2061,10 @@
                             GenericArgKind::Lifetime(_) => self
                                 .next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
                                 .into(),
-                            GenericArgKind::Type(_) => self
-                                .next_ty_var(TypeVariableOrigin {
-                                    span: DUMMY_SP,
-                                    param_def_id: None,
-                                })
-                                .into(),
-                            GenericArgKind::Const(arg) => self
-                                .next_const_var(
-                                    arg.ty(),
-                                    ConstVariableOrigin { span: DUMMY_SP, param_def_id: None },
-                                )
-                                .into(),
+                            GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(),
+                            GenericArgKind::Const(arg) => {
+                                self.next_const_var(arg.ty(), DUMMY_SP).into()
+                            }
                         }
                     } else {
                         arg
@@ -2234,7 +2441,7 @@
                     type Result = ControlFlow<Option<&'v hir::Expr<'v>>>;
                     fn visit_stmt(&mut self, ex: &'v hir::Stmt<'v>) -> Self::Result {
                         if let hir::StmtKind::Let(&hir::LetStmt { pat, init, .. }) = ex.kind
-                            && let Binding(_, _, ident, ..) = pat.kind
+                            && let hir::PatKind::Binding(_, _, ident, ..) = pat.kind
                             && ident.name == self.ident_name
                         {
                             ControlFlow::Break(init)
@@ -2835,7 +3042,8 @@
             Some(output_ty) => self.resolve_vars_if_possible(output_ty),
             _ => return,
         };
-        let method_exists = self.method_exists(item_name, output_ty, call.hir_id, return_type);
+        let method_exists =
+            self.method_exists_for_diagnostic(item_name, output_ty, call.hir_id, return_type);
         debug!("suggest_await_before_method: is_method_exist={}", method_exists);
         if method_exists {
             err.span_suggestion_verbose(
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index a4f840d..87b76b9 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -7,20 +7,20 @@
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::{codes::*, struct_span_code_err, Applicability, Diag};
 use rustc_hir as hir;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability,
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, IsSuggestable, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::{bug, span_bug};
 use rustc_session::errors::ExprParenthesesNeeded;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_trait_selection::infer::InferCtxtExt;
 use rustc_trait_selection::traits::error_reporting::suggestions::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{self, FulfillmentError, ObligationCtxt};
+use rustc_trait_selection::traits::{FulfillmentError, ObligationCtxt};
 use rustc_type_ir::TyKind::*;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -219,8 +219,7 @@
                 // e.g., adding `&'a T` and `&'b T`, given `&'x T: Add<&'x T>`, will result
                 // in `&'a T <: &'x T` and `&'b T <: &'x T`, instead of `'a = 'b = 'x`.
                 let lhs_ty = self.check_expr(lhs_expr);
-                let fresh_var = self
-                    .next_ty_var(TypeVariableOrigin { param_def_id: None, span: lhs_expr.span });
+                let fresh_var = self.next_ty_var(lhs_expr.span);
                 self.demand_coerce(lhs_expr, lhs_ty, fresh_var, Some(rhs_expr), AllowTwoPhase::No)
             }
             IsAssign::Yes => {
@@ -239,8 +238,7 @@
         // using this variable as the expected type, which sometimes lets
         // us do better coercions than we would be able to do otherwise,
         // particularly for things like `String + &String`.
-        let rhs_ty_var =
-            self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: rhs_expr.span });
+        let rhs_ty_var = self.next_ty_var(rhs_expr.span);
 
         let result = self.lookup_op_method(
             (lhs_expr, lhs_ty),
@@ -585,7 +583,7 @@
                         if !errors.is_empty() {
                             for error in errors {
                                 if let Some(trait_pred) =
-                                    error.obligation.predicate.to_opt_poly_trait_pred()
+                                    error.obligation.predicate.as_trait_clause()
                                 {
                                     let output_associated_item = match error.obligation.cause.code()
                                     {
@@ -799,9 +797,9 @@
                     );
 
                     if operand_ty.has_non_region_param() {
-                        let predicates = errors.iter().filter_map(|error| {
-                            error.obligation.predicate.to_opt_poly_trait_pred()
-                        });
+                        let predicates = errors
+                            .iter()
+                            .filter_map(|error| error.obligation.predicate.as_trait_clause());
                         for pred in predicates {
                             self.err_ctxt().suggest_restricting_param_bound(
                                 &mut err,
@@ -887,7 +885,7 @@
         let input_types = opt_rhs_ty.as_slice();
         let cause = self.cause(
             span,
-            traits::BinOp {
+            ObligationCauseCode::BinOp {
                 lhs_hir_id: lhs_expr.hir_id,
                 rhs_hir_id: opt_rhs_expr.map(|expr| expr.hir_id),
                 rhs_span: opt_rhs_expr.map(|expr| expr.span),
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index 8c7ae7f..b9b220d 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -9,9 +9,9 @@
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, Pat, PatKind};
 use rustc_infer::infer;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
+use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::hygiene::DesugaringKind;
@@ -19,7 +19,7 @@
 use rustc_span::symbol::{kw, sym, Ident};
 use rustc_span::{BytePos, Span, DUMMY_SP};
 use rustc_target::abi::FieldIdx;
-use rustc_trait_selection::traits::{ObligationCause, Pattern};
+use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
 use ty::VariantDef;
 
 use std::cmp;
@@ -74,23 +74,28 @@
     ///              found type `std::result::Result<_, _>`
     /// ```
     span: Option<Span>,
+    /// The [`HirId`] of the top-level pattern.
+    hir_id: HirId,
 }
 
 #[derive(Copy, Clone)]
 struct PatInfo<'tcx, 'a> {
     binding_mode: ByRef,
-    max_ref_mutbl: Mutability,
-    top_info: TopInfo<'tcx>,
-    decl_origin: Option<DeclOrigin<'a>>,
+    max_ref_mutbl: MutblCap,
+    top_info: &'a TopInfo<'tcx>,
+    decl_origin: Option<DeclOrigin<'tcx>>,
 
     /// The depth of current pattern
     current_depth: u32,
 }
 
 impl<'tcx> FnCtxt<'_, 'tcx> {
-    fn pattern_cause(&self, ti: TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
-        let code =
-            Pattern { span: ti.span, root_ty: ti.expected, origin_expr: ti.origin_expr.is_some() };
+    fn pattern_cause(&self, ti: &TopInfo<'tcx>, cause_span: Span) -> ObligationCause<'tcx> {
+        let code = ObligationCauseCode::Pattern {
+            span: ti.span,
+            root_ty: ti.expected,
+            origin_expr: ti.origin_expr.is_some(),
+        };
         self.cause(cause_span, code)
     }
 
@@ -99,7 +104,7 @@
         cause_span: Span,
         expected: Ty<'tcx>,
         actual: Ty<'tcx>,
-        ti: TopInfo<'tcx>,
+        ti: &TopInfo<'tcx>,
     ) -> Option<Diag<'tcx>> {
         let mut diag =
             self.demand_eqtype_with_origin(&self.pattern_cause(ti, cause_span), expected, actual)?;
@@ -116,7 +121,7 @@
         cause_span: Span,
         expected: Ty<'tcx>,
         actual: Ty<'tcx>,
-        ti: TopInfo<'tcx>,
+        ti: &TopInfo<'tcx>,
     ) {
         if let Some(err) = self.demand_eqtype_pat_diag(cause_span, expected, actual, ti) {
             err.emit();
@@ -125,22 +130,61 @@
 }
 
 /// Mode for adjusting the expected type and binding mode.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 enum AdjustMode {
     /// Peel off all immediate reference types.
     Peel,
     /// Reset binding mode to the initial mode.
     /// Used for destructuring assignment, where we don't want any match ergonomics.
     Reset,
-    /// Produced by ref patterns.
-    /// Reset the binding mode to the initial mode,
-    /// and if the old biding mode was by-reference
-    /// with mutability matching the pattern,
-    /// mark the pattern as having consumed this reference.
-    ResetAndConsumeRef(Mutability),
     /// Pass on the input binding mode and expected type.
     Pass,
 }
 
+/// `ref mut` patterns (explicit or match-ergonomics)
+/// are not allowed behind an `&` reference.
+///
+/// This includes explicit `ref mut` behind `&` patterns
+/// that match against `&mut` references,
+/// where the code would have compiled
+/// had the pattern been written as `&mut`.
+/// However, the borrow checker will not catch
+/// this last case, so we need to throw an error ourselves.
+#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+enum MutblCap {
+    /// Mutability restricted to immutable.
+    Not,
+
+    /// Mutability restricted to immutable, but only because of the pattern
+    /// (not the scrutinee type).
+    ///
+    /// The contained span, if present, points to an `&` pattern
+    /// that is the reason for the restriction,
+    /// and which will be reported in a diagnostic.
+    WeaklyNot(Option<Span>),
+
+    /// No restriction on mutability
+    Mut,
+}
+
+impl MutblCap {
+    #[must_use]
+    fn cap_to_weakly_not(self, span: Option<Span>) -> Self {
+        match self {
+            MutblCap::Not => MutblCap::Not,
+            _ => MutblCap::WeaklyNot(span),
+        }
+    }
+
+    #[must_use]
+    fn as_mutbl(self) -> Mutability {
+        match self {
+            MutblCap::Not | MutblCap::WeaklyNot(_) => Mutability::Not,
+            MutblCap::Mut => Mutability::Mut,
+        }
+    }
+}
+
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Type check the given top level pattern against the `expected` type.
     ///
@@ -158,11 +202,11 @@
         origin_expr: Option<&'tcx hir::Expr<'tcx>>,
         decl_origin: Option<DeclOrigin<'tcx>>,
     ) {
-        let info = TopInfo { expected, origin_expr, span };
+        let info = TopInfo { expected, origin_expr, span, hir_id: pat.hir_id };
         let pat_info = PatInfo {
             binding_mode: ByRef::No,
-            max_ref_mutbl: Mutability::Mut,
-            top_info: info,
+            max_ref_mutbl: MutblCap::Mut,
+            top_info: &info,
             decl_origin,
             current_depth: 0,
         };
@@ -170,14 +214,13 @@
     }
 
     /// Type check the given `pat` against the `expected` type
-    /// with the provided `def_bm` (default binding mode).
+    /// with the provided `binding_mode` (default binding mode).
     ///
     /// Outside of this module, `check_pat_top` should always be used.
     /// Conversely, inside this module, `check_pat_top` should never be used.
     #[instrument(level = "debug", skip(self, pat_info))]
     fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'tcx, '_>) {
-        let PatInfo { binding_mode: def_bm, max_ref_mutbl, top_info: ti, current_depth, .. } =
-            pat_info;
+        let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info;
 
         let path_res = match &pat.kind {
             PatKind::Path(qpath) => Some(
@@ -186,10 +229,10 @@
             _ => None,
         };
         let adjust_mode = self.calc_adjust_mode(pat, path_res.map(|(res, ..)| res));
-        let (expected, def_bm, max_ref_mutbl, ref_pattern_already_consumed) =
-            self.calc_default_binding_mode(pat, expected, def_bm, adjust_mode, max_ref_mutbl);
+        let (expected, binding_mode, max_ref_mutbl) =
+            self.calc_default_binding_mode(pat, expected, binding_mode, adjust_mode, max_ref_mutbl);
         let pat_info = PatInfo {
-            binding_mode: def_bm,
+            binding_mode,
             max_ref_mutbl,
             top_info: ti,
             decl_origin: pat_info.decl_origin,
@@ -202,8 +245,8 @@
             PatKind::Never => expected,
             PatKind::Lit(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
             PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
-            PatKind::Binding(ba, var_id, _, sub) => {
-                self.check_pat_ident(pat, ba, var_id, sub, expected, pat_info)
+            PatKind::Binding(ba, var_id, ident, sub) => {
+                self.check_pat_ident(pat, ba, var_id, ident, sub, expected, pat_info)
             }
             PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
                 self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
@@ -225,14 +268,7 @@
             }
             PatKind::Box(inner) => self.check_pat_box(pat.span, inner, expected, pat_info),
             PatKind::Deref(inner) => self.check_pat_deref(pat.span, inner, expected, pat_info),
-            PatKind::Ref(inner, mutbl) => self.check_pat_ref(
-                pat,
-                inner,
-                mutbl,
-                expected,
-                pat_info,
-                ref_pattern_already_consumed,
-            ),
+            PatKind::Ref(inner, mutbl) => self.check_pat_ref(pat, inner, mutbl, expected, pat_info),
             PatKind::Slice(before, slice, after) => {
                 self.check_pat_slice(pat.span, before, slice, after, expected, pat_info)
             }
@@ -285,52 +321,22 @@
 
     /// Compute the new expected type and default binding mode from the old ones
     /// as well as the pattern form we are currently checking.
-    ///
-    /// Last entry is only relevant for ref patterns (`&` and `&mut`);
-    /// if `true`, then the ref pattern consumed a match ergonomics inserted reference
-    /// and so does no need to match against a reference in the scrutinee type.
     fn calc_default_binding_mode(
         &self,
         pat: &'tcx Pat<'tcx>,
         expected: Ty<'tcx>,
         def_br: ByRef,
         adjust_mode: AdjustMode,
-        max_ref_mutbl: Mutability,
-    ) -> (Ty<'tcx>, ByRef, Mutability, bool) {
-        if let ByRef::Yes(mutbl) = def_br {
-            debug_assert!(mutbl <= max_ref_mutbl);
+        max_ref_mutbl: MutblCap,
+    ) -> (Ty<'tcx>, ByRef, MutblCap) {
+        if let ByRef::Yes(Mutability::Mut) = def_br {
+            debug_assert!(max_ref_mutbl == MutblCap::Mut);
         }
         match adjust_mode {
-            AdjustMode::Pass => (expected, def_br, max_ref_mutbl, false),
-            AdjustMode::Reset => (expected, ByRef::No, Mutability::Mut, false),
-            AdjustMode::ResetAndConsumeRef(ref_pat_mutbl) => {
-                let mutbls_match = def_br == ByRef::Yes(ref_pat_mutbl);
-                if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
-                    if mutbls_match {
-                        debug!("consuming inherited reference");
-                        (expected, ByRef::No, cmp::min(max_ref_mutbl, ref_pat_mutbl), true)
-                    } else {
-                        let (new_ty, new_bm, max_ref_mutbl) = if ref_pat_mutbl == Mutability::Mut {
-                            self.peel_off_references(
-                                pat,
-                                expected,
-                                def_br,
-                                Mutability::Not,
-                                max_ref_mutbl,
-                            )
-                        } else {
-                            (expected, def_br.cap_ref_mutability(Mutability::Not), Mutability::Not)
-                        };
-                        (new_ty, new_bm, max_ref_mutbl, false)
-                    }
-                } else {
-                    (expected, ByRef::No, max_ref_mutbl, mutbls_match)
-                }
-            }
+            AdjustMode::Pass => (expected, def_br, max_ref_mutbl),
+            AdjustMode::Reset => (expected, ByRef::No, MutblCap::Mut),
             AdjustMode::Peel => {
-                let peeled =
-                    self.peel_off_references(pat, expected, def_br, Mutability::Mut, max_ref_mutbl);
-                (peeled.0, peeled.1, peeled.2, false)
+                self.peel_off_references(pat, expected, def_br, Mutability::Mut, max_ref_mutbl)
             }
         }
     }
@@ -376,17 +382,8 @@
                 // a reference type wherefore peeling doesn't give up any expressiveness.
                 _ => AdjustMode::Peel,
             },
-            // When encountering a `& mut? pat` pattern, reset to "by value".
-            // This is so that `x` and `y` here are by value, as they appear to be:
-            //
-            // ```
-            // match &(&22, &44) {
-            //   (&x, &y) => ...
-            // }
-            // ```
-            //
-            // See issue #46688.
-            PatKind::Ref(_, mutbl) => AdjustMode::ResetAndConsumeRef(*mutbl),
+            // Ref patterns are complicated, we handle them in `check_pat_ref`.
+            PatKind::Ref(..) => AdjustMode::Pass,
             // A `_` pattern works with any expected type, so there's no need to do anything.
             PatKind::Wild
             // A malformed pattern doesn't have an expected type, so let's just accept any type.
@@ -412,8 +409,8 @@
         expected: Ty<'tcx>,
         mut def_br: ByRef,
         max_peelable_mutability: Mutability,
-        mut max_ref_mutability: Mutability,
-    ) -> (Ty<'tcx>, ByRef, Mutability) {
+        mut max_ref_mutability: MutblCap,
+    ) -> (Ty<'tcx>, ByRef, MutblCap) {
         let mut expected = self.try_structurally_resolve_type(pat.span, expected);
         // Peel off as many `&` or `&mut` from the scrutinee type as possible. For example,
         // for `match &&&mut Some(5)` the loop runs three times, aborting when it reaches
@@ -447,9 +444,9 @@
         }
 
         if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
-            def_br = def_br.cap_ref_mutability(max_ref_mutability);
+            def_br = def_br.cap_ref_mutability(max_ref_mutability.as_mutbl());
             if def_br == ByRef::Yes(Mutability::Not) {
-                max_ref_mutability = Mutability::Not;
+                max_ref_mutability = MutblCap::Not;
             }
         }
 
@@ -469,7 +466,7 @@
         span: Span,
         lt: &hir::Expr<'tcx>,
         expected: Ty<'tcx>,
-        ti: TopInfo<'tcx>,
+        ti: &TopInfo<'tcx>,
     ) -> Ty<'tcx> {
         // We've already computed the type above (when checking for a non-ref pat),
         // so avoid computing it again.
@@ -539,7 +536,7 @@
         lhs: Option<&'tcx hir::Expr<'tcx>>,
         rhs: Option<&'tcx hir::Expr<'tcx>>,
         expected: Ty<'tcx>,
-        ti: TopInfo<'tcx>,
+        ti: &TopInfo<'tcx>,
     ) -> Ty<'tcx> {
         let calc_side = |opt_expr: Option<&'tcx hir::Expr<'tcx>>| match opt_expr {
             None => None,
@@ -666,8 +663,9 @@
     fn check_pat_ident(
         &self,
         pat: &'tcx Pat<'tcx>,
-        ba: BindingMode,
+        user_bind_annot: BindingMode,
         var_id: HirId,
+        ident: Ident,
         sub: Option<&'tcx Pat<'tcx>>,
         expected: Ty<'tcx>,
         pat_info: PatInfo<'tcx, '_>,
@@ -675,24 +673,44 @@
         let PatInfo { binding_mode: def_br, top_info: ti, .. } = pat_info;
 
         // Determine the binding mode...
-        let bm = match ba {
+        let bm = match user_bind_annot {
+            // `mut` resets binding mode on edition <= 2021
             BindingMode(ByRef::No, Mutability::Mut)
                 if !(pat.span.at_least_rust_2024()
                     && self.tcx.features().mut_preserve_binding_mode_2024)
                     && matches!(def_br, ByRef::Yes(_)) =>
             {
-                // `mut x` resets the binding mode in edition <= 2021.
-                self.tcx.emit_node_span_lint(
-                    rustc_lint::builtin::DEREFERENCING_MUT_BINDING,
-                    pat.hir_id,
-                    pat.span,
-                    errors::DereferencingMutBinding { span: pat.span },
-                );
+                self.typeck_results
+                    .borrow_mut()
+                    .rust_2024_migration_desugared_pats_mut()
+                    .insert(pat_info.top_info.hir_id);
                 BindingMode(ByRef::No, Mutability::Mut)
             }
             BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
-            BindingMode(ByRef::Yes(_), _) => ba,
+            BindingMode(ByRef::Yes(_), _) => user_bind_annot,
         };
+
+        if bm.0 == ByRef::Yes(Mutability::Mut)
+            && let MutblCap::WeaklyNot(and_pat_span) = pat_info.max_ref_mutbl
+        {
+            let mut err = struct_span_code_err!(
+                self.tcx.dcx(),
+                ident.span,
+                E0596,
+                "cannot borrow as mutable inside an `&` pattern"
+            );
+
+            if let Some(span) = and_pat_span {
+                err.span_suggestion(
+                    span,
+                    "replace this `&` with `&mut`",
+                    "&mut ",
+                    Applicability::MachineApplicable,
+                );
+            }
+            err.emit();
+        }
+
         // ...and store it in a side table:
         self.typeck_results.borrow_mut().pat_binding_modes_mut().insert(pat.hir_id, bm);
 
@@ -718,7 +736,7 @@
         // If there are multiple arms, make sure they all agree on
         // what the type of the binding `x` ought to be.
         if var_id != pat.hir_id {
-            self.check_binding_alt_eq_ty(ba, pat.span, var_id, local_ty, ti);
+            self.check_binding_alt_eq_ty(user_bind_annot, pat.span, var_id, local_ty, ti);
         }
 
         if let Some(p) = sub {
@@ -737,7 +755,7 @@
         span: Span,
         var_id: HirId,
         ty: Ty<'tcx>,
-        ti: TopInfo<'tcx>,
+        ti: &TopInfo<'tcx>,
     ) {
         let var_ty = self.local_ty(span, var_id);
         if let Some(mut err) = self.demand_eqtype_pat_diag(span, var_ty, ty, ti) {
@@ -919,8 +937,8 @@
         inner: &Pat<'_>,
     ) -> Result<(), ErrorGuaranteed> {
         if let PatKind::Binding(..) = inner.kind
-            && let Some(mt) = self.shallow_resolve(expected).builtin_deref(true)
-            && let ty::Dynamic(..) = mt.ty.kind()
+            && let Some(pointee_ty) = self.shallow_resolve(expected).builtin_deref(true)
+            && let ty::Dynamic(..) = pointee_ty.kind()
         {
             // This is "x = dyn SomeTrait" being reduced from
             // "let &x = &dyn SomeTrait" or "let box x = Box<dyn SomeTrait>", an error.
@@ -979,7 +997,7 @@
         qpath: &hir::QPath<'_>,
         path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
         expected: Ty<'tcx>,
-        ti: TopInfo<'tcx>,
+        ti: &TopInfo<'tcx>,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
 
@@ -1419,8 +1437,7 @@
         }
         let max_len = cmp::max(expected_len, elements.len());
 
-        let element_tys_iter =
-            (0..max_len).map(|_| self.next_ty_var(TypeVariableOrigin { param_def_id: None, span }));
+        let element_tys_iter = (0..max_len).map(|_| self.next_ty_var(span));
         let element_tys = tcx.mk_type_list_from_iter(element_tys_iter);
         let pat_ty = Ty::new_tup(tcx, element_tys);
         if let Some(err) = self.demand_eqtype_pat_diag(span, expected, pat_ty, pat_info.top_info) {
@@ -1676,7 +1693,7 @@
         unmentioned_fields: &mut Vec<(&'tcx ty::FieldDef, Ident)>,
         pat: &'tcx Pat<'tcx>,
         variant: &ty::VariantDef,
-        args: &'tcx ty::List<ty::GenericArg<'tcx>>,
+        args: ty::GenericArgsRef<'tcx>,
     ) -> Diag<'tcx> {
         let tcx = self.tcx;
         let (field_names, t, plural) = if let [field] = inexistent_fields {
@@ -2046,8 +2063,7 @@
             Ok(()) => {
                 // Here, `demand::subtype` is good enough, but I don't
                 // think any errors can be introduced by using `demand::eqtype`.
-                let inner_ty =
-                    self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: inner.span });
+                let inner_ty = self.next_ty_var(inner.span);
                 let box_ty = Ty::new_box(tcx, inner_ty);
                 self.demand_eqtype_pat(span, expected, box_ty, pat_info.top_info);
                 (box_ty, inner_ty)
@@ -2105,75 +2121,145 @@
         &self,
         pat: &'tcx Pat<'tcx>,
         inner: &'tcx Pat<'tcx>,
-        mutbl: Mutability,
-        expected: Ty<'tcx>,
-        pat_info: PatInfo<'tcx, '_>,
-        consumed_inherited_ref: bool,
+        pat_mutbl: Mutability,
+        mut expected: Ty<'tcx>,
+        mut pat_info: PatInfo<'tcx, '_>,
     ) -> Ty<'tcx> {
-        if consumed_inherited_ref
-            && pat.span.at_least_rust_2024()
-            && self.tcx.features().ref_pat_eat_one_layer_2024
-        {
-            self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
-            self.check_pat(inner, expected, pat_info);
-            expected
+        // FIXME: repace with `bool` once final decision on 1 vs 2 layers is made
+        #[derive(Clone, Copy, Debug, PartialEq, Eq)]
+        enum MatchErgonomicsMode {
+            EatOneLayer,
+            EatTwoLayers,
+            Legacy,
+        }
+
+        let match_ergonomics_mode =
+            if pat.span.at_least_rust_2024() && self.tcx.features().ref_pat_eat_one_layer_2024 {
+                MatchErgonomicsMode::EatOneLayer
+            } else if self.tcx.features().ref_pat_everywhere {
+                MatchErgonomicsMode::EatTwoLayers
+            } else {
+                MatchErgonomicsMode::Legacy
+            };
+
+        let mut inherited_ref_mutbl_match = false;
+        if match_ergonomics_mode != MatchErgonomicsMode::Legacy {
+            if pat_mutbl == Mutability::Not {
+                // Prevent the inner pattern from binding with `ref mut`.
+                pat_info.max_ref_mutbl = pat_info.max_ref_mutbl.cap_to_weakly_not(
+                    inner.span.find_ancestor_inside(pat.span).map(|end| pat.span.until(end)),
+                );
+            }
+
+            if let ByRef::Yes(inh_mut) = pat_info.binding_mode {
+                inherited_ref_mutbl_match = pat_mutbl <= inh_mut;
+            }
+
+            if inherited_ref_mutbl_match {
+                pat_info.binding_mode = ByRef::No;
+                if match_ergonomics_mode == MatchErgonomicsMode::EatOneLayer {
+                    self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
+                    self.check_pat(inner, expected, pat_info);
+                    return expected;
+                }
+            } else if match_ergonomics_mode == MatchErgonomicsMode::EatOneLayer
+                && pat_mutbl == Mutability::Mut
+            {
+                // `&mut` patterns pell off `&` references
+                let (new_expected, new_bm, max_ref_mutbl) = self.peel_off_references(
+                    pat,
+                    expected,
+                    pat_info.binding_mode,
+                    Mutability::Not,
+                    pat_info.max_ref_mutbl,
+                );
+                expected = new_expected;
+                pat_info.binding_mode = new_bm;
+                pat_info.max_ref_mutbl = max_ref_mutbl;
+            }
         } else {
-            let tcx = self.tcx;
-            let expected = self.shallow_resolve(expected);
-            let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
-                Ok(()) => {
-                    // `demand::subtype` would be good enough, but using `eqtype` turns
-                    // out to be equally general. See (note_1) for details.
+            // Reset binding mode on old editions
 
-                    // Take region, inner-type from expected type if we can,
-                    // to avoid creating needless variables. This also helps with
-                    // the bad interactions of the given hack detailed in (note_1).
-                    debug!("check_pat_ref: expected={:?}", expected);
-                    match *expected.kind() {
-                        ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty),
-                        _ => {
-                            if consumed_inherited_ref && self.tcx.features().ref_pat_everywhere {
-                                // We already matched against a match-ergonmics inserted reference,
-                                // so we don't need to match against a reference from the original type.
-                                // Save this infor for use in lowering later
-                                self.typeck_results
-                                    .borrow_mut()
-                                    .skipped_ref_pats_mut()
-                                    .insert(pat.hir_id);
-                                (expected, expected)
-                            } else {
-                                let inner_ty = self.next_ty_var(TypeVariableOrigin {
-                                    param_def_id: None,
-                                    span: inner.span,
-                                });
-                                let ref_ty = self.new_ref_ty(pat.span, mutbl, inner_ty);
-                                debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
-                                let err = self.demand_eqtype_pat_diag(
-                                    pat.span,
-                                    expected,
-                                    ref_ty,
-                                    pat_info.top_info,
-                                );
+            if pat_info.binding_mode != ByRef::No {
+                pat_info.binding_mode = ByRef::No;
 
-                                // Look for a case like `fn foo(&foo: u32)` and suggest
-                                // `fn foo(foo: &u32)`
-                                if let Some(mut err) = err {
-                                    self.borrow_pat_suggestion(&mut err, pat);
-                                    err.emit();
-                                }
-                                (ref_ty, inner_ty)
-                            }
+                self.typeck_results
+                    .borrow_mut()
+                    .rust_2024_migration_desugared_pats_mut()
+                    .insert(pat_info.top_info.hir_id);
+            }
+
+            pat_info.max_ref_mutbl = MutblCap::Mut;
+        }
+
+        let tcx = self.tcx;
+        expected = self.try_structurally_resolve_type(pat.span, expected);
+        let (ref_ty, inner_ty) = match self.check_dereferenceable(pat.span, expected, inner) {
+            Ok(()) => {
+                // `demand::subtype` would be good enough, but using `eqtype` turns
+                // out to be equally general. See (note_1) for details.
+
+                // Take region, inner-type from expected type if we can,
+                // to avoid creating needless variables. This also helps with
+                // the bad interactions of the given hack detailed in (note_1).
+                debug!("check_pat_ref: expected={:?}", expected);
+                match *expected.kind() {
+                    ty::Ref(_, r_ty, r_mutbl) if r_mutbl == pat_mutbl => {
+                        if r_mutbl == Mutability::Not
+                            && match_ergonomics_mode != MatchErgonomicsMode::Legacy
+                        {
+                            pat_info.max_ref_mutbl = MutblCap::Not;
                         }
+
+                        (expected, r_ty)
+                    }
+
+                    // `&` pattern eats `&mut` reference
+                    ty::Ref(_, r_ty, Mutability::Mut)
+                        if pat_mutbl == Mutability::Not
+                            && match_ergonomics_mode != MatchErgonomicsMode::Legacy =>
+                    {
+                        (expected, r_ty)
+                    }
+
+                    _ if inherited_ref_mutbl_match
+                        && match_ergonomics_mode == MatchErgonomicsMode::EatTwoLayers =>
+                    {
+                        // We already matched against a match-ergonmics inserted reference,
+                        // so we don't need to match against a reference from the original type.
+                        // Save this info for use in lowering later
+                        self.typeck_results.borrow_mut().skipped_ref_pats_mut().insert(pat.hir_id);
+                        (expected, expected)
+                    }
+
+                    _ => {
+                        let inner_ty = self.next_ty_var(inner.span);
+                        let ref_ty = self.new_ref_ty(pat.span, pat_mutbl, inner_ty);
+                        debug!("check_pat_ref: demanding {:?} = {:?}", expected, ref_ty);
+                        let err = self.demand_eqtype_pat_diag(
+                            pat.span,
+                            expected,
+                            ref_ty,
+                            pat_info.top_info,
+                        );
+
+                        // Look for a case like `fn foo(&foo: u32)` and suggest
+                        // `fn foo(foo: &u32)`
+                        if let Some(mut err) = err {
+                            self.borrow_pat_suggestion(&mut err, pat);
+                            err.emit();
+                        }
+                        (ref_ty, inner_ty)
                     }
                 }
-                Err(guar) => {
-                    let err = Ty::new_error(tcx, guar);
-                    (err, err)
-                }
-            };
-            self.check_pat(inner, inner_ty, pat_info);
-            ref_ty
-        }
+            }
+            Err(guar) => {
+                let err = Ty::new_error(tcx, guar);
+                (err, err)
+            }
+        };
+        self.check_pat(inner, inner_ty, pat_info);
+        ref_ty
     }
 
     /// Create a reference type with a fresh region variable.
@@ -2194,8 +2280,7 @@
 
         let tcx = self.tcx;
         let len = before.len();
-        let ty_var_origin = TypeVariableOrigin { param_def_id: None, span };
-        let inner_ty = self.next_ty_var(ty_var_origin);
+        let inner_ty = self.next_ty_var(span);
 
         Some(Ty::new_array(tcx, inner_ty, len.try_into().unwrap()))
     }
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index bce43b3..515e1b5 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -4,8 +4,8 @@
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir_analysis::autoderef::Autoderef;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::InferOk;
+use rustc_middle::span_bug;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCoercion};
 use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutability};
 use rustc_middle::ty::{self, Ty};
@@ -20,8 +20,8 @@
         oprnd_expr: &'tcx hir::Expr<'tcx>,
         oprnd_ty: Ty<'tcx>,
     ) -> Option<Ty<'tcx>> {
-        if let Some(mt) = oprnd_ty.builtin_deref(true) {
-            return Some(mt.ty);
+        if let Some(ty) = oprnd_ty.builtin_deref(true) {
+            return Some(ty);
         }
 
         let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?;
@@ -37,7 +37,7 @@
         } else {
             span_bug!(expr.span, "input to deref is not a ref?");
         }
-        let ty = self.make_overloaded_place_return_type(method).ty;
+        let ty = self.make_overloaded_place_return_type(method);
         self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method);
         Some(ty)
     }
@@ -147,8 +147,7 @@
             // If some lookup succeeds, write callee into table and extract index/element
             // type from the method signature.
             // If some lookup succeeded, install method in table
-            let input_ty =
-                self.next_ty_var(TypeVariableOrigin { param_def_id: None, span: base_expr.span });
+            let input_ty = self.next_ty_var(base_expr.span);
             let method =
                 self.try_overloaded_place_op(expr.span, self_ty, &[input_ty], PlaceOp::Index);
 
@@ -175,7 +174,7 @@
 
                 self.write_method_call_and_enforce_effects(expr.hir_id, expr.span, method);
 
-                return Some((input_ty, self.make_overloaded_place_return_type(method).ty));
+                return Some((input_ty, self.make_overloaded_place_return_type(method)));
             }
         }
 
@@ -344,8 +343,7 @@
             .borrow()
             .expr_ty_adjusted(base_expr)
             .builtin_deref(false)
-            .expect("place op takes something that is not a ref")
-            .ty;
+            .expect("place op takes something that is not a ref");
 
         let arg_ty = match op {
             PlaceOp::Deref => None,
diff --git a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
index 34ce0ab..805f36d 100644
--- a/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
+++ b/compiler/rustc_hir_typeck/src/rvalue_scopes.rs
@@ -2,6 +2,7 @@
 use hir::def_id::DefId;
 use hir::Node;
 use rustc_hir as hir;
+use rustc_middle::bug;
 use rustc_middle::middle::region::{RvalueCandidateType, Scope, ScopeTree};
 use rustc_middle::ty::RvalueScopes;
 
diff --git a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
index 31ce271..19d6481 100644
--- a/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
+++ b/compiler/rustc_hir_typeck/src/typeck_root_ctxt.rs
@@ -5,6 +5,7 @@
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{HirId, HirIdMap};
 use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
+use rustc_middle::span_bug;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefIdMap;
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 2bf4f51..9d16f0d 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -47,6 +47,7 @@
     self, ClosureSizeProfileData, Ty, TyCtxt, TypeVisitableExt as _, TypeckResults, UpvarArgs,
     UpvarCapture,
 };
+use rustc_middle::{bug, span_bug};
 use rustc_session::lint;
 use rustc_span::sym;
 use rustc_span::{BytePos, Pos, Span, Symbol};
@@ -252,12 +253,9 @@
             }
         }
 
-        euv::ExprUseVisitor::new(
+        let _ = euv::ExprUseVisitor::new(
+            &FnCtxt::new(self, self.tcx.param_env(closure_def_id), closure_def_id),
             &mut delegate,
-            &self.infcx,
-            closure_def_id,
-            self.param_env,
-            &self.typeck_results.borrow(),
         )
         .consume_body(body);
 
@@ -421,7 +419,7 @@
                         [],
                         tupled_upvars_ty_for_borrow,
                         false,
-                        hir::Unsafety::Normal,
+                        hir::Safety::Safe,
                         rustc_target::spec::abi::Abi::Rust,
                     ),
                     self.tcx.mk_bound_variable_kinds(&[ty::BoundVariableKind::Region(
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index 0a40ffb..f798dee 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -9,6 +9,7 @@
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::HirId;
 use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
+use rustc_middle::span_bug;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion};
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder};
@@ -346,6 +347,7 @@
             _ => {}
         };
 
+        self.visit_rust_2024_migration_desugared_pats(p.hir_id);
         self.visit_skipped_ref_pats(p.hir_id);
         self.visit_pat_adjustments(p.span, p.hir_id);
 
@@ -655,6 +657,22 @@
         }
     }
 
+    #[instrument(skip(self), level = "debug")]
+    fn visit_rust_2024_migration_desugared_pats(&mut self, hir_id: hir::HirId) {
+        if self
+            .fcx
+            .typeck_results
+            .borrow_mut()
+            .rust_2024_migration_desugared_pats_mut()
+            .remove(hir_id)
+        {
+            debug!(
+                "node is a pat whose match ergonomics are desugared by the Rust 2024 migration lint"
+            );
+            self.typeck_results.rust_2024_migration_desugared_pats_mut().insert(hir_id);
+        }
+    }
+
     #[instrument(skip(self, span), level = "debug")]
     fn visit_pat_adjustments(&mut self, span: Span, hir_id: HirId) {
         let adjustment = self.fcx.typeck_results.borrow_mut().pat_adjustments_mut().remove(hir_id);
diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl
index 64f52ea..8f1c4ad 100644
--- a/compiler/rustc_infer/messages.ftl
+++ b/compiler/rustc_infer/messages.ftl
@@ -164,7 +164,10 @@
 infer_lf_bound_not_satisfied = lifetime bound not satisfied
 infer_lifetime_mismatch = lifetime mismatch
 
-infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl ->
+infer_lifetime_param_suggestion = consider {$is_reuse ->
+    [true] reusing
+    *[false] introducing
+} a named lifetime parameter{$is_impl ->
     [true] {" "}and update trait if needed
     *[false] {""}
 }
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index 2acaeac..8bb0dc3 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -1,9 +1,11 @@
 use hir::GenericParamKind;
+use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::{
     codes::*, Applicability, Diag, DiagMessage, DiagStyledString, EmissionGuarantee, IntoDiagArg,
     MultiSpan, SubdiagMessageOp, Subdiagnostic,
 };
 use rustc_hir as hir;
+use rustc_hir::intravisit::{walk_ty, Visitor};
 use rustc_hir::FnRetTy;
 use rustc_macros::{Diagnostic, Subdiagnostic};
 use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath;
@@ -355,31 +357,33 @@
         _f: &F,
     ) {
         let mut mk_suggestion = || {
-            let (
-                hir::Ty { kind: hir::TyKind::Ref(lifetime_sub, _), .. },
-                hir::Ty { kind: hir::TyKind::Ref(lifetime_sup, _), .. },
-            ) = (self.ty_sub, self.ty_sup)
-            else {
-                return false;
-            };
-
-            if !lifetime_sub.is_anonymous() || !lifetime_sup.is_anonymous() {
-                return false;
-            };
-
             let Some(anon_reg) = self.tcx.is_suitable_region(self.sub) else {
                 return false;
             };
 
             let node = self.tcx.hir_node_by_def_id(anon_reg.def_id);
             let is_impl = matches!(&node, hir::Node::ImplItem(_));
-            let generics = match node {
+            let (generics, parent_generics) = match node {
                 hir::Node::Item(&hir::Item {
                     kind: hir::ItemKind::Fn(_, ref generics, ..),
                     ..
                 })
                 | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
-                | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => generics,
+                | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => (
+                    generics,
+                    match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.def_id))
+                    {
+                        hir::Node::Item(hir::Item {
+                            kind: hir::ItemKind::Trait(_, _, ref generics, ..),
+                            ..
+                        })
+                        | hir::Node::Item(hir::Item {
+                            kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }),
+                            ..
+                        }) => Some(generics),
+                        _ => None,
+                    },
+                ),
                 _ => return false,
             };
 
@@ -390,24 +394,112 @@
                 .map(|p| p.name.ident().name)
                 .find(|i| *i != kw::UnderscoreLifetime);
             let introduce_new = suggestion_param_name.is_none();
+
+            let mut default = "'a".to_string();
+            if let Some(parent_generics) = parent_generics {
+                let used: FxHashSet<_> = parent_generics
+                    .params
+                    .iter()
+                    .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { .. }))
+                    .map(|p| p.name.ident().name)
+                    .filter(|i| *i != kw::UnderscoreLifetime)
+                    .map(|l| l.to_string())
+                    .collect();
+                if let Some(lt) =
+                    ('a'..='z').map(|it| format!("'{it}")).find(|it| !used.contains(it))
+                {
+                    // We want a lifetime that *isn't* present in the `trait` or `impl` that assoc
+                    // `fn` belongs to. We could suggest reusing one of their lifetimes, but it is
+                    // likely to be an over-constraining lifetime requirement, so we always add a
+                    // lifetime to the `fn`.
+                    default = lt;
+                }
+            }
             let suggestion_param_name =
-                suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| "'a".to_owned());
+                suggestion_param_name.map(|n| n.to_string()).unwrap_or_else(|| default);
 
-            debug!(?lifetime_sup.ident.span);
-            debug!(?lifetime_sub.ident.span);
-            let make_suggestion = |ident: Ident| {
-                let sugg = if ident.name == kw::Empty {
-                    format!("{suggestion_param_name}, ")
-                } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
-                    format!("{suggestion_param_name} ")
-                } else {
-                    suggestion_param_name.clone()
-                };
-                (ident.span, sugg)
+            struct ImplicitLifetimeFinder {
+                suggestions: Vec<(Span, String)>,
+                suggestion_param_name: String,
+            }
+
+            impl<'v> Visitor<'v> for ImplicitLifetimeFinder {
+                fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) {
+                    let make_suggestion = |ident: Ident| {
+                        if ident.name == kw::Empty && ident.span.is_empty() {
+                            format!("{}, ", self.suggestion_param_name)
+                        } else if ident.name == kw::UnderscoreLifetime && ident.span.is_empty() {
+                            format!("{} ", self.suggestion_param_name)
+                        } else {
+                            self.suggestion_param_name.clone()
+                        }
+                    };
+                    match ty.kind {
+                        hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
+                            for segment in path.segments {
+                                if let Some(args) = segment.args {
+                                    if args.args.iter().all(|arg| {
+                                        matches!(
+                                            arg,
+                                            hir::GenericArg::Lifetime(lifetime)
+                                            if lifetime.ident.name == kw::Empty
+                                        )
+                                    }) {
+                                        self.suggestions.push((
+                                            segment.ident.span.shrink_to_hi(),
+                                            format!(
+                                                "<{}>",
+                                                args.args
+                                                    .iter()
+                                                    .map(|_| self.suggestion_param_name.clone())
+                                                    .collect::<Vec<_>>()
+                                                    .join(", ")
+                                            ),
+                                        ));
+                                    } else {
+                                        for arg in args.args {
+                                            if let hir::GenericArg::Lifetime(lifetime) = arg
+                                                && lifetime.is_anonymous()
+                                            {
+                                                self.suggestions.push((
+                                                    lifetime.ident.span,
+                                                    make_suggestion(lifetime.ident),
+                                                ));
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                        hir::TyKind::Ref(lifetime, ..) if lifetime.is_anonymous() => {
+                            self.suggestions
+                                .push((lifetime.ident.span, make_suggestion(lifetime.ident)));
+                        }
+                        _ => {}
+                    }
+                    walk_ty(self, ty);
+                }
+            }
+            let mut visitor = ImplicitLifetimeFinder {
+                suggestions: vec![],
+                suggestion_param_name: suggestion_param_name.clone(),
             };
-            let mut suggestions =
-                vec![make_suggestion(lifetime_sub.ident), make_suggestion(lifetime_sup.ident)];
-
+            if let Some(fn_decl) = node.fn_decl()
+                && let hir::FnRetTy::Return(ty) = fn_decl.output
+            {
+                visitor.visit_ty(ty);
+            }
+            if visitor.suggestions.is_empty() {
+                // Do not suggest constraining the `&self` param, but rather the return type.
+                // If that is wrong (because it is not sufficient), a follow up error will tell the
+                // user to fix it. This way we lower the chances of *over* constraining, but still
+                // get the cake of "correctly" contrained in two steps.
+                visitor.visit_ty(self.ty_sup);
+            }
+            visitor.visit_ty(self.ty_sub);
+            if visitor.suggestions.is_empty() {
+                return false;
+            }
             if introduce_new {
                 let new_param_suggestion = if let Some(first) =
                     generics.params.iter().find(|p| !p.name.ident().span.is_empty())
@@ -417,15 +509,16 @@
                     (generics.span, format!("<{suggestion_param_name}>"))
                 };
 
-                suggestions.push(new_param_suggestion);
+                visitor.suggestions.push(new_param_suggestion);
             }
-
-            diag.multipart_suggestion(
+            diag.multipart_suggestion_verbose(
                 fluent::infer_lifetime_param_suggestion,
-                suggestions,
+                visitor.suggestions,
                 Applicability::MaybeIncorrect,
             );
             diag.arg("is_impl", is_impl);
+            diag.arg("is_reuse", !introduce_new);
+
             true
         };
         if mk_suggestion() && self.add_note {
diff --git a/compiler/rustc_infer/src/errors/note_and_explain.rs b/compiler/rustc_infer/src/errors/note_and_explain.rs
index 70d9487..f0b336c 100644
--- a/compiler/rustc_infer/src/errors/note_and_explain.rs
+++ b/compiler/rustc_infer/src/errors/note_and_explain.rs
@@ -1,6 +1,7 @@
 use crate::fluent_generated as fluent;
 use crate::infer::error_reporting::nice_region_error::find_anon_type;
 use rustc_errors::{Diag, EmissionGuarantee, IntoDiagArg, SubdiagMessageOp, Subdiagnostic};
+use rustc_middle::bug;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::{symbol::kw, Span};
 
@@ -69,16 +70,8 @@
 
             ty::RePlaceholder(_) | ty::ReError(_) => return None,
 
-            // FIXME(#13998) RePlaceholder should probably print like
-            // ReLateParam rather than dumping Debug output on the user.
-            //
-            // We shouldn't really be having unification failures with ReVar
-            // and ReBound though.
-            //
-            // FIXME(@lcnr): figure out why we have to handle `ReBound`
-            // here, this feels somewhat off.
             ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => {
-                (alt_span, "revar", format!("{region:?}"))
+                bug!("unexpected region for DescriptionCtx: {:?}", region);
             }
         };
         Some(DescriptionCtx { span, kind, arg })
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index 0f21d39..16057b6 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -27,6 +27,7 @@
 
 use super::*;
 
+use rustc_middle::bug;
 use rustc_middle::ty::relate::{Relate, TypeRelation};
 use rustc_middle::ty::{Const, ImplSubject};
 
@@ -384,19 +385,31 @@
         a: Self,
         b: Self,
     ) -> TypeTrace<'tcx> {
-        use GenericArgKind::*;
         TypeTrace {
             cause: cause.clone(),
             values: match (a.unpack(), b.unpack()) {
-                (Lifetime(a), Lifetime(b)) => Regions(ExpectedFound::new(a_is_expected, a, b)),
-                (Type(a), Type(b)) => Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())),
-                (Const(a), Const(b)) => {
+                (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => {
+                    Regions(ExpectedFound::new(a_is_expected, a, b))
+                }
+                (GenericArgKind::Type(a), GenericArgKind::Type(b)) => {
+                    Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
+                }
+                (GenericArgKind::Const(a), GenericArgKind::Const(b)) => {
                     Terms(ExpectedFound::new(a_is_expected, a.into(), b.into()))
                 }
 
-                (Lifetime(_), Type(_) | Const(_))
-                | (Type(_), Lifetime(_) | Const(_))
-                | (Const(_), Lifetime(_) | Type(_)) => {
+                (
+                    GenericArgKind::Lifetime(_),
+                    GenericArgKind::Type(_) | GenericArgKind::Const(_),
+                )
+                | (
+                    GenericArgKind::Type(_),
+                    GenericArgKind::Lifetime(_) | GenericArgKind::Const(_),
+                )
+                | (
+                    GenericArgKind::Const(_),
+                    GenericArgKind::Lifetime(_) | GenericArgKind::Type(_),
+                ) => {
                     bug!("relating different kinds: {a:?} {b:?}")
                 }
             },
@@ -436,6 +449,20 @@
         a: Self,
         b: Self,
     ) -> TypeTrace<'tcx> {
+        TypeTrace {
+            cause: cause.clone(),
+            values: Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())),
+        }
+    }
+}
+
+impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> {
+    fn to_trace(
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: Self,
+        b: Self,
+    ) -> TypeTrace<'tcx> {
         TypeTrace { cause: cause.clone(), values: Aliases(ExpectedFound::new(a_is_expected, a, b)) }
     }
 }
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 4d712e9..27b06c4 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -9,6 +9,7 @@
     Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues,
 };
 use crate::infer::InferCtxt;
+use rustc_middle::bug;
 use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::GenericArg;
 use rustc_middle::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs
index f95cc13..de0e15e 100644
--- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs
+++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs
@@ -8,6 +8,7 @@
 
 use crate::infer::canonical::{Canonical, CanonicalVarValues};
 use rustc_macros::extension;
+use rustc_middle::bug;
 use rustc_middle::ty::fold::{FnMutDelegate, TypeFoldable};
 use rustc_middle::ty::GenericArgKind;
 use rustc_middle::ty::{self, TyCtxt};
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index 734fa91..1abb808 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -21,8 +21,7 @@
 //!
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
-use crate::infer::ConstVariableOrigin;
-use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin};
+use crate::infer::{InferCtxt, RegionVariableOrigin};
 use rustc_index::IndexVec;
 use rustc_middle::infer::unify_key::EffectVarValue;
 use rustc_middle::ty::fold::TypeFoldable;
@@ -114,10 +113,9 @@
         match cv_info.kind {
             CanonicalVarKind::Ty(ty_kind) => {
                 let ty = match ty_kind {
-                    CanonicalTyVarKind::General(ui) => self.next_ty_var_in_universe(
-                        TypeVariableOrigin { param_def_id: None, span },
-                        universe_map(ui),
-                    ),
+                    CanonicalTyVarKind::General(ui) => {
+                        self.next_ty_var_in_universe(span, universe_map(ui))
+                    }
 
                     CanonicalTyVarKind::Int => self.next_int_var(),
 
@@ -145,13 +143,9 @@
                 ty::Region::new_placeholder(self.tcx, placeholder_mapped).into()
             }
 
-            CanonicalVarKind::Const(ui, ty) => self
-                .next_const_var_in_universe(
-                    ty,
-                    ConstVariableOrigin { param_def_id: None, span },
-                    universe_map(ui),
-                )
-                .into(),
+            CanonicalVarKind::Const(ui, ty) => {
+                self.next_const_var_in_universe(ty, span, universe_map(ui)).into()
+            }
             CanonicalVarKind::Effect => {
                 let vid = self
                     .inner
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index b948067..1732913 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -25,6 +25,7 @@
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, BoundVar, Ty, TyCtxt};
 use rustc_middle::ty::{GenericArg, GenericArgKind};
+use rustc_middle::{bug, span_bug};
 use std::fmt::Debug;
 use std::iter;
 
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 635bbca..46a7e7b 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -69,10 +69,11 @@
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::lang_items::LangItem;
 use rustc_macros::extension;
+use rustc_middle::bug;
 use rustc_middle::dep_graph::DepContext;
-use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError};
+use rustc_middle::ty::print::{with_forced_trimmed_paths, PrintError, PrintTraitRefExt as _};
 use rustc_middle::ty::relate::{self, RelateResult, TypeRelation};
-use rustc_middle::ty::ToPredicate;
+use rustc_middle::ty::Upcast;
 use rustc_middle::ty::{
     self, error::TypeError, IsSuggestable, List, Region, Ty, TyCtxt, TypeFoldable,
     TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@@ -172,11 +173,9 @@
 
         ty::ReError(_) => return,
 
-        // We shouldn't really be having unification failures with ReVar
-        // and ReBound though.
-        //
-        // FIXME(@lcnr): Figure out whether this is reachable and if so, why.
-        ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => (format!("lifetime `{region}`"), alt_span),
+        ty::ReVar(_) | ty::ReBound(..) | ty::ReErased => {
+            bug!("unexpected region for note_and_explain_region: {:?}", region);
+        }
     };
 
     emit_msg_span(err, prefix, description, span, suffix);
@@ -412,7 +411,7 @@
                     .kind()
                     .map_bound(|kind| match kind {
                         ty::ClauseKind::Projection(projection_predicate)
-                            if projection_predicate.projection_ty.def_id == item_def_id =>
+                            if projection_predicate.projection_term.def_id == item_def_id =>
                         {
                             projection_predicate.term.ty()
                         }
@@ -517,7 +516,7 @@
 
                     RegionResolutionError::CannotNormalize(clause, origin) => {
                         let clause: ty::Clause<'tcx> =
-                            clause.map_bound(ty::ClauseKind::TypeOutlives).to_predicate(self.tcx);
+                            clause.map_bound(ty::ClauseKind::TypeOutlives).upcast(self.tcx);
                         self.tcx
                             .dcx()
                             .struct_span_err(origin.span(), format!("cannot normalize `{clause}`"))
@@ -885,9 +884,10 @@
                 err.help("...or use `match` instead of `let...else`");
             }
             _ => {
-                if let ObligationCauseCode::BindingObligation(_, span)
-                | ObligationCauseCode::ExprBindingObligation(_, span, ..) =
+                if let ObligationCauseCode::WhereClause(_, span)
+                | ObligationCauseCode::WhereClauseInExpr(_, span, ..) =
                     cause.code().peel_derives()
+                    && !span.is_dummy()
                     && let TypeError::RegionsPlaceholderMismatch = terr
                 {
                     err.span_note(*span, "the lifetime requirement is introduced here");
@@ -1053,8 +1053,8 @@
 
         // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
         // ^^^^^^
-        values.0.push(sig1.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety);
-        values.1.push(sig2.unsafety.prefix_str(), sig1.unsafety != sig2.unsafety);
+        values.0.push(sig1.safety.prefix_str(), sig1.safety != sig2.safety);
+        values.1.push(sig2.safety.prefix_str(), sig1.safety != sig2.safety);
 
         // unsafe extern "C" for<'a> fn(&'a T) -> &'a T
         //        ^^^^^^^^^^
@@ -1928,7 +1928,7 @@
                                     self.tcx
                                         .signature_unclosure(
                                             args.as_closure().sig(),
-                                            rustc_hir::Unsafety::Normal,
+                                            rustc_hir::Safety::Safe,
                                         )
                                         .to_string(),
                                 ),
@@ -2014,7 +2014,6 @@
         trace: &TypeTrace<'tcx>,
         terr: TypeError<'tcx>,
     ) -> Vec<TypeErrorAdditionalDiags> {
-        use crate::traits::ObligationCauseCode::{BlockTailExpression, MatchExpressionArm};
         let mut suggestions = Vec::new();
         let span = trace.cause.span();
         let values = self.resolve_vars_if_possible(trace.values);
@@ -2081,8 +2080,11 @@
             }
         }
         let code = trace.cause.code();
-        if let &(MatchExpressionArm(box MatchExpressionArmCause { source, .. })
-        | BlockTailExpression(.., source)) = code
+        if let &(ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
+            source,
+            ..
+        })
+        | ObligationCauseCode::BlockTailExpression(.., source)) = code
             && let hir::MatchSource::TryDesugar(_) = source
             && let Some((expected_ty, found_ty, _)) = self.values_str(trace.values)
         {
@@ -2507,7 +2509,7 @@
             let generics = self.tcx.generics_of(lifetime_scope);
             let mut used_names =
                 iter::successors(Some(generics), |g| g.parent.map(|p| self.tcx.generics_of(p)))
-                    .flat_map(|g| &g.params)
+                    .flat_map(|g| &g.own_params)
                     .filter(|p| matches!(p.kind, ty::GenericParamDefKind::Lifetime))
                     .map(|p| p.name)
                     .collect::<Vec<_>>();
@@ -2775,19 +2777,17 @@
 #[extension(pub trait ObligationCauseExt<'tcx>)]
 impl<'tcx> ObligationCause<'tcx> {
     fn as_failure_code(&self, terr: TypeError<'tcx>) -> FailureCode {
-        use self::FailureCode::*;
-        use crate::traits::ObligationCauseCode::*;
         match self.code() {
-            IfExpressionWithNoElse => Error0317,
-            MainFunctionType => Error0580,
-            CompareImplItemObligation { .. }
-            | MatchExpressionArm(_)
-            | IfExpression { .. }
-            | LetElse
-            | StartFunctionType
-            | LangFunctionType(_)
-            | IntrinsicType
-            | MethodReceiver => Error0308,
+            ObligationCauseCode::IfExpressionWithNoElse => FailureCode::Error0317,
+            ObligationCauseCode::MainFunctionType => FailureCode::Error0580,
+            ObligationCauseCode::CompareImplItem { .. }
+            | ObligationCauseCode::MatchExpressionArm(_)
+            | ObligationCauseCode::IfExpression { .. }
+            | ObligationCauseCode::LetElse
+            | ObligationCauseCode::StartFunctionType
+            | ObligationCauseCode::LangFunctionType(_)
+            | ObligationCauseCode::IntrinsicType
+            | ObligationCauseCode::MethodReceiver => FailureCode::Error0308,
 
             // In the case where we have no more specific thing to
             // say, also take a look at the error code, maybe we can
@@ -2796,10 +2796,10 @@
                 TypeError::CyclicTy(ty)
                     if ty.is_closure() || ty.is_coroutine() || ty.is_coroutine_closure() =>
                 {
-                    Error0644
+                    FailureCode::Error0644
                 }
-                TypeError::IntrinsicCast => Error0308,
-                _ => Error0308,
+                TypeError::IntrinsicCast => FailureCode::Error0308,
+                _ => FailureCode::Error0308,
             },
         }
     }
@@ -2809,36 +2809,51 @@
         span: Span,
         subdiags: Vec<TypeErrorAdditionalDiags>,
     ) -> ObligationCauseFailureCode {
-        use crate::traits::ObligationCauseCode::*;
         match self.code() {
-            CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => {
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => {
                 ObligationCauseFailureCode::MethodCompat { span, subdiags }
             }
-            CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => {
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => {
                 ObligationCauseFailureCode::TypeCompat { span, subdiags }
             }
-            CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => {
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
                 ObligationCauseFailureCode::ConstCompat { span, subdiags }
             }
-            BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => {
+            ObligationCauseCode::BlockTailExpression(.., hir::MatchSource::TryDesugar(_)) => {
                 ObligationCauseFailureCode::TryCompat { span, subdiags }
             }
-            MatchExpressionArm(box MatchExpressionArmCause { source, .. }) => match source {
+            ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
+                source, ..
+            }) => match source {
                 hir::MatchSource::TryDesugar(_) => {
                     ObligationCauseFailureCode::TryCompat { span, subdiags }
                 }
                 _ => ObligationCauseFailureCode::MatchCompat { span, subdiags },
             },
-            IfExpression { .. } => ObligationCauseFailureCode::IfElseDifferent { span, subdiags },
-            IfExpressionWithNoElse => ObligationCauseFailureCode::NoElse { span },
-            LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags },
-            MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span },
-            StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags },
-            &LangFunctionType(lang_item_name) => {
+            ObligationCauseCode::IfExpression { .. } => {
+                ObligationCauseFailureCode::IfElseDifferent { span, subdiags }
+            }
+            ObligationCauseCode::IfExpressionWithNoElse => {
+                ObligationCauseFailureCode::NoElse { span }
+            }
+            ObligationCauseCode::LetElse => {
+                ObligationCauseFailureCode::NoDiverge { span, subdiags }
+            }
+            ObligationCauseCode::MainFunctionType => {
+                ObligationCauseFailureCode::FnMainCorrectType { span }
+            }
+            ObligationCauseCode::StartFunctionType => {
+                ObligationCauseFailureCode::FnStartCorrectType { span, subdiags }
+            }
+            &ObligationCauseCode::LangFunctionType(lang_item_name) => {
                 ObligationCauseFailureCode::FnLangCorrectType { span, subdiags, lang_item_name }
             }
-            IntrinsicType => ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags },
-            MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags },
+            ObligationCauseCode::IntrinsicType => {
+                ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags }
+            }
+            ObligationCauseCode::MethodReceiver => {
+                ObligationCauseFailureCode::MethodCorrectType { span, subdiags }
+            }
 
             // In the case where we have no more specific thing to
             // say, also take a look at the error code, maybe we can
@@ -2858,22 +2873,21 @@
     }
 
     fn as_requirement_str(&self) -> &'static str {
-        use crate::traits::ObligationCauseCode::*;
         match self.code() {
-            CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => {
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => {
                 "method type is compatible with trait"
             }
-            CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => {
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => {
                 "associated type is compatible with trait"
             }
-            CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => {
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
                 "const is compatible with trait"
             }
-            MainFunctionType => "`main` function has the correct type",
-            StartFunctionType => "`#[start]` function has the correct type",
-            LangFunctionType(_) => "lang item function has the correct type",
-            IntrinsicType => "intrinsic has the correct type",
-            MethodReceiver => "method receiver has the correct type",
+            ObligationCauseCode::MainFunctionType => "`main` function has the correct type",
+            ObligationCauseCode::StartFunctionType => "`#[start]` function has the correct type",
+            ObligationCauseCode::LangFunctionType(_) => "lang item function has the correct type",
+            ObligationCauseCode::IntrinsicType => "intrinsic has the correct type",
+            ObligationCauseCode::MethodReceiver => "method receiver has the correct type",
             _ => "types are compatible",
         }
     }
@@ -2884,16 +2898,17 @@
 
 impl IntoDiagArg for ObligationCauseAsDiagArg<'_> {
     fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
-        use crate::traits::ObligationCauseCode::*;
         let kind = match self.0.code() {
-            CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => "method_compat",
-            CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => "type_compat",
-            CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => "const_compat",
-            MainFunctionType => "fn_main_correct_type",
-            StartFunctionType => "fn_start_correct_type",
-            LangFunctionType(_) => "fn_lang_correct_type",
-            IntrinsicType => "intrinsic_correct_type",
-            MethodReceiver => "method_correct_type",
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Fn, .. } => "method_compat",
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Type, .. } => "type_compat",
+            ObligationCauseCode::CompareImplItem { kind: ty::AssocKind::Const, .. } => {
+                "const_compat"
+            }
+            ObligationCauseCode::MainFunctionType => "fn_main_correct_type",
+            ObligationCauseCode::StartFunctionType => "fn_start_correct_type",
+            ObligationCauseCode::LangFunctionType(_) => "fn_lang_correct_type",
+            ObligationCauseCode::IntrinsicType => "intrinsic_correct_type",
+            ObligationCauseCode::MethodReceiver => "method_correct_type",
             _ => "other",
         }
         .into();
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index a2a38d1..98fd790 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -3,7 +3,6 @@
     SourceKindMultiSuggestion, SourceKindSubdiag,
 };
 use crate::infer::error_reporting::TypeErrCtxt;
-use crate::infer::type_variable::TypeVariableOrigin;
 use crate::infer::InferCtxt;
 use rustc_errors::{codes::*, Diag, IntoDiagArg};
 use rustc_hir as hir;
@@ -12,8 +11,9 @@
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource};
+use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
-use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableValue};
+use rustc_middle::infer::unify_key::ConstVariableValue;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
 use rustc_middle::ty::print::{FmtPrinter, PrettyPrinter, Print, Printer};
 use rustc_middle::ty::{
@@ -168,7 +168,7 @@
                 let closure_sig = args.as_closure().sig();
                 Ty::new_fn_ptr(
                     self.tcx,
-                    self.tcx.signature_unclosure(closure_sig, hir::Unsafety::Normal),
+                    self.tcx.signature_unclosure(closure_sig, hir::Safety::Safe),
                 )
             }
             _ => ty.super_fold_with(self),
@@ -522,7 +522,7 @@
                 infer_subdiags.push(SourceKindSubdiag::GenericLabel {
                     span,
                     is_type,
-                    param_name: generics.params[argument_index].name.to_string(),
+                    param_name: generics.own_params[argument_index].name.to_string(),
                     parent_exists,
                     parent_prefix,
                     parent_name,
@@ -542,18 +542,10 @@
 
                             match arg.unpack() {
                                 GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"),
-                                GenericArgKind::Type(_) => self
-                                    .next_ty_var(TypeVariableOrigin {
-                                        span: DUMMY_SP,
-                                        param_def_id: None,
-                                    })
-                                    .into(),
-                                GenericArgKind::Const(arg) => self
-                                    .next_const_var(
-                                        arg.ty(),
-                                        ConstVariableOrigin { span: DUMMY_SP, param_def_id: None },
-                                    )
-                                    .into(),
+                                GenericArgKind::Type(_) => self.next_ty_var(DUMMY_SP).into(),
+                                GenericArgKind::Const(arg) => {
+                                    self.next_const_var(arg.ty(), DUMMY_SP).into()
+                                }
                             }
                         }))
                         .unwrap();
@@ -569,9 +561,7 @@
                 }
             }
             InferSourceKind::FullyQualifiedMethodCall { receiver, successor, args, def_id } => {
-                let placeholder = Some(
-                    self.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }),
-                );
+                let placeholder = Some(self.next_ty_var(DUMMY_SP));
                 if let Some(args) = args.make_suggestable(self.infcx.tcx, true, placeholder) {
                     let mut printer = fmt_printer(self, Namespace::ValueNS);
                     printer.print_def_path(def_id, args).unwrap();
@@ -605,9 +595,7 @@
                 }
             }
             InferSourceKind::ClosureReturn { ty, data, should_wrap_expr } => {
-                let placeholder = Some(
-                    self.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }),
-                );
+                let placeholder = Some(self.next_ty_var(DUMMY_SP));
                 if let Some(ty) = ty.make_suggestable(self.infcx.tcx, true, placeholder) {
                     let ty_info = ty_to_string(self, ty, None);
                     multi_suggestions.push(SourceKindMultiSuggestion::new_closure_return(
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
index b93b8dc..45dce0a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mismatched_static_lifetime.rs
@@ -13,6 +13,7 @@
 use rustc_errors::{ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::intravisit::Visitor;
+use rustc_middle::bug;
 use rustc_middle::ty::TypeVisitor;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -32,17 +33,20 @@
         // If we added a "points at argument expression" obligation, we remove it here, we care
         // about the original obligation only.
         let code = match cause.code() {
-            ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => &*parent_code,
+            ObligationCauseCode::FunctionArg { parent_code, .. } => &*parent_code,
             code => code,
         };
         let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else {
             return None;
         };
-        let (ObligationCauseCode::BindingObligation(_, binding_span)
-        | ObligationCauseCode::ExprBindingObligation(_, binding_span, ..)) = *parent.code()
+        let (ObligationCauseCode::WhereClause(_, binding_span)
+        | ObligationCauseCode::WhereClauseInExpr(_, binding_span, ..)) = *parent.code()
         else {
             return None;
         };
+        if binding_span.is_dummy() {
+            return None;
+        }
 
         // FIXME: we should point at the lifetime
         let multi_span: MultiSpan = vec![binding_span].into();
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index 01e75d59..e125f18 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -10,9 +10,10 @@
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{Diag, IntoDiagArg};
 use rustc_hir::def::Namespace;
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
+use rustc_middle::bug;
 use rustc_middle::ty::error::ExpectedFound;
-use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
+use rustc_middle::ty::print::{FmtPrinter, Print, PrintTraitRefExt as _, RegionHighlightMode};
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, RePlaceholder, Region, TyCtxt};
 
@@ -240,8 +241,9 @@
         let span = cause.span();
 
         let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
-            if let ObligationCauseCode::ItemObligation(def_id)
-            | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code()
+            if let ObligationCauseCode::WhereClause(def_id, span)
+            | ObligationCauseCode::WhereClauseInExpr(def_id, span, ..) = *cause.code()
+                && def_id != CRATE_DEF_ID.to_def_id()
             {
                 (
                     true,
@@ -407,10 +409,8 @@
             {
                 let closure_sig = self_ty.map(|closure| {
                     if let ty::Closure(_, args) = closure.kind() {
-                        self.tcx().signature_unclosure(
-                            args.as_closure().sig(),
-                            rustc_hir::Unsafety::Normal,
-                        )
+                        self.tcx()
+                            .signature_unclosure(args.as_closure().sig(), rustc_hir::Safety::Safe)
                     } else {
                         bug!("type is not longer closure");
                     }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 0bbabef..8a1e3a7 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -214,8 +214,8 @@
                 _ => cause.code(),
             }
             && let (
-                &ObligationCauseCode::ItemObligation(item_def_id)
-                | &ObligationCauseCode::ExprItemObligation(item_def_id, ..),
+                &ObligationCauseCode::WhereClause(item_def_id, _)
+                | &ObligationCauseCode::WhereClauseInExpr(item_def_id, ..),
                 None,
             ) = (code, override_error_code)
         {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index b4cf727..7f3e237 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -4,13 +4,13 @@
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::{Subtype, ValuePairs};
-use crate::traits::ObligationCauseCode::CompareImplItemObligation;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
+use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::print::RegionHighlightMode;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
@@ -31,7 +31,8 @@
             _,
         ) = error.clone()
             && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
-            && let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code()
+            && let ObligationCauseCode::CompareImplItem { trait_item_def_id, .. } =
+                sub_trace.cause.code()
             && sub_trace.values == sup_trace.values
             && let ValuePairs::PolySigs(ExpectedFound { expected, found }) = sub_trace.values
         {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index 3ae1165..00dd20a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -357,21 +357,22 @@
             infer::Subtype(box ref trace)
                 if matches!(
                     &trace.cause.code().peel_derives(),
-                    ObligationCauseCode::BindingObligation(..)
-                        | ObligationCauseCode::ExprBindingObligation(..)
+                    ObligationCauseCode::WhereClause(..)
+                        | ObligationCauseCode::WhereClauseInExpr(..)
                 ) =>
             {
                 // Hack to get around the borrow checker because trace.cause has an `Rc`.
-                if let ObligationCauseCode::BindingObligation(_, span)
-                | ObligationCauseCode::ExprBindingObligation(_, span, ..) =
+                if let ObligationCauseCode::WhereClause(_, span)
+                | ObligationCauseCode::WhereClauseInExpr(_, span, ..) =
                     &trace.cause.code().peel_derives()
+                    && !span.is_dummy()
                 {
                     let span = *span;
                     self.report_concrete_failure(placeholder_origin, sub, sup)
                         .with_span_note(span, "the lifetime requirement is introduced here")
                 } else {
                     unreachable!(
-                        "control flow ensures we have a `BindingObligation` or `ExprBindingObligation` here..."
+                        "control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..."
                     )
                 }
             }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index 6a42f9b..f2fe433 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -452,7 +452,7 @@
                     }
                     (ty::FnPtr(sig), ty::FnDef(def_id, _))
                     | (ty::FnDef(def_id, _), ty::FnPtr(sig)) => {
-                        if tcx.fn_sig(def_id).skip_binder().unsafety() < sig.unsafety() {
+                        if tcx.fn_sig(def_id).skip_binder().safety() < sig.safety() {
                             diag.note(
                                 "unsafe functions cannot be coerced into safe function pointers",
                             );
@@ -629,8 +629,7 @@
                     | hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), .. }),
             )
         );
-        let impl_comparison =
-            matches!(cause_code, ObligationCauseCode::CompareImplItemObligation { .. });
+        let impl_comparison = matches!(cause_code, ObligationCauseCode::CompareImplItem { .. });
         let assoc = tcx.associated_item(proj_ty.def_id);
         if impl_comparison {
             // We do not want to suggest calling functions when the reason of the
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index bf470bb..75479de 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -167,7 +167,7 @@
             exp_span, exp_found.expected, exp_found.found,
         );
 
-        if let ObligationCauseCode::CompareImplItemObligation { .. } = cause.code() {
+        if let ObligationCauseCode::CompareImplItem { .. } = cause.code() {
             return;
         }
 
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index ef9c407..b2d8952 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -32,6 +32,7 @@
 //! inferencer knows "so far".
 use super::InferCtxt;
 use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::bug;
 use rustc_middle::infer::unify_key::ToType;
 use rustc_middle::ty::fold::TypeFolder;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeVisitableExt};
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index 5ae7f8b..72944c9c 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -20,6 +20,7 @@
 use rustc_middle::ty::{ReBound, RePlaceholder, ReVar};
 use rustc_middle::ty::{ReEarlyParam, ReErased, ReError, ReLateParam, ReStatic};
 use rustc_middle::ty::{Region, RegionVid};
+use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 use std::fmt;
 
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index bb53aec..8d40114 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -44,6 +44,7 @@
 use rustc_middle::ty::{self, GenericParamDefKind, InferConst, InferTy, Ty, TyCtxt};
 use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid};
 use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef};
+use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
 use snapshot::undo_log::InferCtxtUndoLogs;
@@ -368,34 +369,44 @@
         }
     }
 
-    fn root_ty_var(&self, vid: TyVid) -> TyVid {
-        self.root_var(vid)
-    }
-
-    fn probe_ty_var(&self, vid: TyVid) -> Option<Ty<'tcx>> {
-        self.probe_ty_var(vid).ok()
-    }
-
-    fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> Option<ty::Region<'tcx>> {
-        let re = self
-            .inner
-            .borrow_mut()
-            .unwrap_region_constraints()
-            .opportunistic_resolve_var(self.tcx, vid);
-        if *re == ty::ReVar(vid) { None } else { Some(re) }
-    }
-
-    fn root_ct_var(&self, vid: ConstVid) -> ConstVid {
-        self.root_const_var(vid)
-    }
-
-    fn probe_ct_var(&self, vid: ConstVid) -> Option<ty::Const<'tcx>> {
-        self.probe_const_var(vid).ok()
+    fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> {
+        self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid)
     }
 
     fn defining_opaque_types(&self) -> &'tcx ty::List<LocalDefId> {
         self.defining_opaque_types
     }
+
+    fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> {
+        match self.probe_ty_var(vid) {
+            Ok(ty) => ty,
+            Err(_) => Ty::new_var(self.tcx, self.root_var(vid)),
+        }
+    }
+
+    fn opportunistic_resolve_int_var(&self, vid: IntVid) -> Ty<'tcx> {
+        self.opportunistic_resolve_int_var(vid)
+    }
+
+    fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> Ty<'tcx> {
+        self.opportunistic_resolve_float_var(vid)
+    }
+
+    fn opportunistic_resolve_ct_var(&self, vid: ConstVid, ty: Ty<'tcx>) -> ty::Const<'tcx> {
+        match self.probe_const_var(vid) {
+            Ok(ct) => ct,
+            Err(_) => ty::Const::new_var(self.tcx, self.root_const_var(vid), ty),
+        }
+    }
+
+    fn opportunistic_resolve_effect_var(&self, vid: EffectVid, ty: Ty<'tcx>) -> ty::Const<'tcx> {
+        match self.probe_effect_var(vid) {
+            Some(ct) => ct,
+            None => {
+                ty::Const::new_infer(self.tcx, InferConst::EffectVar(self.root_effect_var(vid)), ty)
+            }
+        }
+    }
 }
 
 /// See the `error_reporting` module for more details.
@@ -403,7 +414,7 @@
 pub enum ValuePairs<'tcx> {
     Regions(ExpectedFound<ty::Region<'tcx>>),
     Terms(ExpectedFound<ty::Term<'tcx>>),
-    Aliases(ExpectedFound<ty::AliasTy<'tcx>>),
+    Aliases(ExpectedFound<ty::AliasTerm<'tcx>>),
     TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
     PolySigs(ExpectedFound<ty::PolyFnSig<'tcx>>),
     ExistentialTraitRef(ExpectedFound<ty::PolyExistentialTraitRef<'tcx>>),
@@ -528,8 +539,8 @@
 
     /// Region variables created as the values for early-bound regions.
     ///
-    /// FIXME(@lcnr): This can also store a `DefId`, similar to
-    /// `TypeVariableOriginKind::TypeParameterDefinition`.
+    /// FIXME(@lcnr): This should also store a `DefId`, similar to
+    /// `TypeVariableOrigin`.
     RegionParameterDefinition(Span, Symbol),
 
     /// Region variables created when instantiating a binder with
@@ -989,41 +1000,50 @@
         self.inner.borrow_mut().type_variables().num_vars()
     }
 
-    pub fn next_ty_var_id(&self, origin: TypeVariableOrigin) -> TyVid {
-        self.inner.borrow_mut().type_variables().new_var(self.universe(), origin)
+    pub fn next_ty_var(&self, span: Span) -> Ty<'tcx> {
+        self.next_ty_var_with_origin(TypeVariableOrigin { span, param_def_id: None })
     }
 
-    pub fn next_ty_var(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
-        Ty::new_var(self.tcx, self.next_ty_var_id(origin))
-    }
-
-    pub fn next_ty_var_id_in_universe(
-        &self,
-        origin: TypeVariableOrigin,
-        universe: ty::UniverseIndex,
-    ) -> TyVid {
-        self.inner.borrow_mut().type_variables().new_var(universe, origin)
-    }
-
-    pub fn next_ty_var_in_universe(
-        &self,
-        origin: TypeVariableOrigin,
-        universe: ty::UniverseIndex,
-    ) -> Ty<'tcx> {
-        let vid = self.next_ty_var_id_in_universe(origin, universe);
+    pub fn next_ty_var_with_origin(&self, origin: TypeVariableOrigin) -> Ty<'tcx> {
+        let vid = self.inner.borrow_mut().type_variables().new_var(self.universe(), origin);
         Ty::new_var(self.tcx, vid)
     }
 
-    pub fn next_const_var(&self, ty: Ty<'tcx>, origin: ConstVariableOrigin) -> ty::Const<'tcx> {
-        ty::Const::new_var(self.tcx, self.next_const_var_id(origin), ty)
+    pub fn next_ty_var_id_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> TyVid {
+        let origin = TypeVariableOrigin { span, param_def_id: None };
+        self.inner.borrow_mut().type_variables().new_var(universe, origin)
+    }
+
+    pub fn next_ty_var_in_universe(&self, span: Span, universe: ty::UniverseIndex) -> Ty<'tcx> {
+        let vid = self.next_ty_var_id_in_universe(span, universe);
+        Ty::new_var(self.tcx, vid)
+    }
+
+    pub fn next_const_var(&self, ty: Ty<'tcx>, span: Span) -> ty::Const<'tcx> {
+        self.next_const_var_with_origin(ty, ConstVariableOrigin { span, param_def_id: None })
+    }
+
+    pub fn next_const_var_with_origin(
+        &self,
+        ty: Ty<'tcx>,
+        origin: ConstVariableOrigin,
+    ) -> ty::Const<'tcx> {
+        let vid = self
+            .inner
+            .borrow_mut()
+            .const_unification_table()
+            .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
+            .vid;
+        ty::Const::new_var(self.tcx, vid, ty)
     }
 
     pub fn next_const_var_in_universe(
         &self,
         ty: Ty<'tcx>,
-        origin: ConstVariableOrigin,
+        span: Span,
         universe: ty::UniverseIndex,
     ) -> ty::Const<'tcx> {
+        let origin = ConstVariableOrigin { span, param_def_id: None };
         let vid = self
             .inner
             .borrow_mut()
@@ -1033,28 +1053,14 @@
         ty::Const::new_var(self.tcx, vid, ty)
     }
 
-    pub fn next_const_var_id(&self, origin: ConstVariableOrigin) -> ConstVid {
-        self.inner
-            .borrow_mut()
-            .const_unification_table()
-            .new_key(ConstVariableValue::Unknown { origin, universe: self.universe() })
-            .vid
-    }
-
-    fn next_int_var_id(&self) -> IntVid {
-        self.inner.borrow_mut().int_unification_table().new_key(None)
-    }
-
     pub fn next_int_var(&self) -> Ty<'tcx> {
-        Ty::new_int_var(self.tcx, self.next_int_var_id())
-    }
-
-    fn next_float_var_id(&self) -> FloatVid {
-        self.inner.borrow_mut().float_unification_table().new_key(None)
+        let vid = self.inner.borrow_mut().int_unification_table().new_key(None);
+        Ty::new_int_var(self.tcx, vid)
     }
 
     pub fn next_float_var(&self) -> Ty<'tcx> {
-        Ty::new_float_var(self.tcx, self.next_float_var_id())
+        let vid = self.inner.borrow_mut().float_unification_table().new_key(None);
+        Ty::new_float_var(self.tcx, vid)
     }
 
     /// Creates a fresh region variable with the next available index.
@@ -1468,24 +1474,13 @@
             fn replace_ty(&mut self, bt: ty::BoundTy) -> Ty<'tcx> {
                 self.map
                     .entry(bt.var)
-                    .or_insert_with(|| {
-                        self.infcx
-                            .next_ty_var(TypeVariableOrigin { param_def_id: None, span: self.span })
-                            .into()
-                    })
+                    .or_insert_with(|| self.infcx.next_ty_var(self.span).into())
                     .expect_ty()
             }
             fn replace_const(&mut self, bv: ty::BoundVar, ty: Ty<'tcx>) -> ty::Const<'tcx> {
                 self.map
                     .entry(bv)
-                    .or_insert_with(|| {
-                        self.infcx
-                            .next_const_var(
-                                ty,
-                                ConstVariableOrigin { param_def_id: None, span: self.span },
-                            )
-                            .into()
-                    })
+                    .or_insert_with(|| self.infcx.next_const_var(ty, self.span).into())
                     .expect_const()
             }
         }
@@ -1892,7 +1887,7 @@
                 SubregionOrigin::ReferenceOutlivesReferent(ref_type, cause.span)
             }
 
-            traits::ObligationCauseCode::CompareImplItemObligation {
+            traits::ObligationCauseCode::CompareImplItem {
                 impl_item_def_id,
                 trait_item_def_id,
                 kind: _,
diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
index b7ee860..8eb3185 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs
@@ -1,4 +1,3 @@
-use super::type_variable::TypeVariableOrigin;
 use super::{DefineOpaqueTypes, InferResult};
 use crate::errors::OpaqueHiddenTypeDiag;
 use crate::infer::{InferCtxt, InferOk};
@@ -65,7 +64,7 @@
                     let span = if span.contains(def_span) { def_span } else { span };
                     let code = traits::ObligationCauseCode::OpaqueReturnType(None);
                     let cause = ObligationCause::new(span, body_id, code);
-                    let ty_var = self.next_ty_var(TypeVariableOrigin { param_def_id: None, span });
+                    let ty_var = self.next_ty_var(span);
                     obligations.extend(
                         self.handle_opaque_type(ty, ty_var, &cause, param_env).unwrap().obligations,
                     );
@@ -589,7 +588,7 @@
                             && !tcx.is_impl_trait_in_trait(projection_ty.def_id)
                             && !self.next_trait_solver() =>
                     {
-                        self.infer_projection(
+                        self.projection_ty_to_infer(
                             param_env,
                             projection_ty,
                             cause.clone(),
diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs
index a7ddf47..e07d181 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/table.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs
@@ -1,4 +1,5 @@
 use rustc_data_structures::undo_log::UndoLogs;
+use rustc_middle::bug;
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty};
 
 use crate::infer::snapshot::undo_log::{InferCtxtUndoLogs, UndoLog};
diff --git a/compiler/rustc_infer/src/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs
index f8dbfdd..5bcb4f2 100644
--- a/compiler/rustc_infer/src/infer/outlives/env.rs
+++ b/compiler/rustc_infer/src/infer/outlives/env.rs
@@ -3,6 +3,7 @@
 use crate::traits::query::OutlivesBound;
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_data_structures::transitive_relation::TransitiveRelationBuilder;
+use rustc_middle::bug;
 use rustc_middle::ty::{self, Region};
 
 use super::explicit_outlives_bounds;
@@ -63,8 +64,7 @@
 /// "Region-bound pairs" tracks outlives relations that are known to
 /// be true, either because of explicit where-clauses like `T: 'a` or
 /// because of implied bounds.
-pub type RegionBoundPairs<'tcx> =
-    FxIndexSet<ty::OutlivesPredicate<GenericKind<'tcx>, Region<'tcx>>>;
+pub type RegionBoundPairs<'tcx> = FxIndexSet<ty::OutlivesPredicate<'tcx, GenericKind<'tcx>>>;
 
 impl<'tcx> OutlivesEnvironment<'tcx> {
     /// Create a builder using `ParamEnv` and add explicit outlives bounds into it.
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index fe32398..32c7905 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -67,6 +67,7 @@
 use crate::infer::{self, GenericKind, InferCtxt, RegionObligation, SubregionOrigin, VerifyBound};
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_data_structures::undo_log::UndoLogs;
+use rustc_middle::bug;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::{
@@ -103,8 +104,12 @@
                 cause.span,
                 sup_type,
                 match cause.code().peel_derives() {
-                    ObligationCauseCode::BindingObligation(_, span)
-                    | ObligationCauseCode::ExprBindingObligation(_, span, ..) => Some(*span),
+                    ObligationCauseCode::WhereClause(_, span)
+                    | ObligationCauseCode::WhereClauseInExpr(_, span, ..)
+                        if !span.is_dummy() =>
+                    {
+                        Some(*span)
+                    }
                     _ => None,
                 },
             )
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index bd981c2..7e977b9 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -94,7 +94,7 @@
     pub fn approx_declared_bounds_from_env(
         &self,
         alias_ty: ty::AliasTy<'tcx>,
-    ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
+    ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> {
         let erased_alias_ty = self.tcx.erase_regions(alias_ty.to_ty(self.tcx));
         self.declared_generic_bounds_from_env_for_erased_ty(erased_alias_ty)
     }
@@ -193,7 +193,7 @@
     fn declared_generic_bounds_from_env(
         &self,
         generic_ty: Ty<'tcx>,
-    ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
+    ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> {
         assert!(matches!(generic_ty.kind(), ty::Param(_) | ty::Placeholder(_)));
         self.declared_generic_bounds_from_env_for_erased_ty(generic_ty)
     }
@@ -213,7 +213,7 @@
     fn declared_generic_bounds_from_env_for_erased_ty(
         &self,
         erased_ty: Ty<'tcx>,
-    ) -> Vec<ty::Binder<'tcx, ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>>> {
+    ) -> Vec<ty::PolyTypeOutlivesPredicate<'tcx>> {
         let tcx = self.tcx;
 
         // To start, collect bounds from user environment. Note that
diff --git a/compiler/rustc_infer/src/infer/projection.rs b/compiler/rustc_infer/src/infer/projection.rs
index e60efe3..1678634 100644
--- a/compiler/rustc_infer/src/infer/projection.rs
+++ b/compiler/rustc_infer/src/infer/projection.rs
@@ -3,7 +3,6 @@
 
 use crate::traits::{Obligation, PredicateObligation};
 
-use super::type_variable::TypeVariableOrigin;
 use super::InferCtxt;
 
 impl<'tcx> InferCtxt<'tcx> {
@@ -13,7 +12,7 @@
     /// of the given projection. This allows us to proceed with projections
     /// while they cannot be resolved yet due to missing information or
     /// simply due to the lack of access to the trait resolution machinery.
-    pub fn infer_projection(
+    pub fn projection_ty_to_infer(
         &self,
         param_env: ty::ParamEnv<'tcx>,
         projection_ty: ty::AliasTy<'tcx>,
@@ -23,12 +22,9 @@
     ) -> Ty<'tcx> {
         debug_assert!(!self.next_trait_solver());
         let def_id = projection_ty.def_id;
-        let ty_var = self.next_ty_var(TypeVariableOrigin {
-            param_def_id: None,
-            span: self.tcx.def_span(def_id),
-        });
+        let ty_var = self.next_ty_var(self.tcx.def_span(def_id));
         let projection = ty::Binder::dummy(ty::PredicateKind::Clause(ty::ClauseKind::Projection(
-            ty::ProjectionPredicate { projection_ty, term: ty_var.into() },
+            ty::ProjectionPredicate { projection_term: projection_ty.into(), term: ty_var.into() },
         )));
         let obligation =
             Obligation::with_depth(self.tcx, cause, recursion_depth, param_env, projection);
diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
index 6e8efa3..255ca52 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -3,6 +3,7 @@
 use rustc_data_structures::fx::FxIndexMap;
 use rustc_data_structures::graph::{scc::Sccs, vec_graph::VecGraph};
 use rustc_index::Idx;
+use rustc_middle::span_bug;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::RelateResult;
 
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 223e6e3..6f755e0 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -17,6 +17,7 @@
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{ReBound, ReVar};
 use rustc_middle::ty::{Region, RegionVid};
+use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 
 use std::ops::Range;
diff --git a/compiler/rustc_infer/src/infer/relate/combine.rs b/compiler/rustc_infer/src/infer/relate/combine.rs
index 8a3125f..101598c 100644
--- a/compiler/rustc_infer/src/infer/relate/combine.rs
+++ b/compiler/rustc_infer/src/infer/relate/combine.rs
@@ -24,11 +24,12 @@
 use super::StructurallyRelateAliases;
 use crate::infer::{DefineOpaqueTypes, InferCtxt, TypeTrace};
 use crate::traits::{Obligation, PredicateObligations};
+use rustc_middle::bug;
 use rustc_middle::infer::canonical::OriginalQueryValues;
 use rustc_middle::infer::unify_key::EffectVarValue;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::relate::{RelateResult, TypeRelation};
-use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, InferConst, Ty, TyCtxt, TypeVisitableExt, Upcast};
 use rustc_middle::ty::{IntType, UintType};
 use rustc_span::Span;
 
@@ -336,7 +337,10 @@
         self.obligations.extend(obligations);
     }
 
-    pub fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>) {
+    pub fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
         self.obligations.extend(obligations.into_iter().map(|to_pred| {
             Obligation::new(self.infcx.tcx, self.trace.cause.clone(), self.param_env, to_pred)
         }))
@@ -359,7 +363,10 @@
     /// Register predicates that must hold in order for this relation to hold. Uses
     /// a default obligation cause, [`ObligationEmittingRelation::register_obligations`] should
     /// be used if control over the obligation causes is required.
-    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>);
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    );
 
     /// Register `AliasRelate` obligation(s) that both types must be related to each other.
     fn register_type_relate_obligation(&mut self, a: Ty<'tcx>, b: Ty<'tcx>);
diff --git a/compiler/rustc_infer/src/infer/relate/generalize.rs b/compiler/rustc_infer/src/infer/relate/generalize.rs
index fb9198b..d4c7d75 100644
--- a/compiler/rustc_infer/src/infer/relate/generalize.rs
+++ b/compiler/rustc_infer/src/infer/relate/generalize.rs
@@ -1,11 +1,12 @@
 use std::mem;
 
 use super::StructurallyRelateAliases;
-use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableValue};
+use crate::infer::type_variable::TypeVariableValue;
 use crate::infer::{InferCtxt, ObligationEmittingRelation, RegionVariableOrigin};
 use rustc_data_structures::sso::SsoHashMap;
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::DefId;
+use rustc_middle::bug;
 use rustc_middle::infer::unify_key::ConstVariableValue;
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
@@ -101,7 +102,7 @@
                         // instead create a new inference variable `?normalized_source`, emitting
                         // `Projection(normalized_source, ?ty_normalized)` and `?normalized_source <: generalized_ty`.
                         relation.register_predicates([ty::ProjectionPredicate {
-                            projection_ty: data,
+                            projection_term: data.into(),
                             term: generalized_ty.into(),
                         }]);
                     }
@@ -357,10 +358,7 @@
         //
         // cc trait-system-refactor-initiative#110
         if self.infcx.next_trait_solver() && !alias.has_escaping_bound_vars() && !self.in_alias {
-            return Ok(self.infcx.next_ty_var_in_universe(
-                TypeVariableOrigin { param_def_id: None, span: self.span },
-                self.for_universe,
-            ));
+            return Ok(self.infcx.next_ty_var_in_universe(self.span, self.for_universe));
         }
 
         let is_nested_alias = mem::replace(&mut self.in_alias, true);
@@ -380,10 +378,7 @@
                     }
 
                     debug!("generalization failure in alias");
-                    Ok(self.infcx.next_ty_var_in_universe(
-                        TypeVariableOrigin { param_def_id: None, span: self.span },
-                        self.for_universe,
-                    ))
+                    Ok(self.infcx.next_ty_var_in_universe(self.span, self.for_universe))
                 }
             }
         };
diff --git a/compiler/rustc_infer/src/infer/relate/glb.rs b/compiler/rustc_infer/src/infer/relate/glb.rs
index b86d1b2..a224a86 100644
--- a/compiler/rustc_infer/src/infer/relate/glb.rs
+++ b/compiler/rustc_infer/src/infer/relate/glb.rs
@@ -140,7 +140,10 @@
         self.fields.param_env
     }
 
-    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
         self.fields.register_predicates(obligations);
     }
 
diff --git a/compiler/rustc_infer/src/infer/relate/lattice.rs b/compiler/rustc_infer/src/infer/relate/lattice.rs
index f9470c9..38e25b0 100644
--- a/compiler/rustc_infer/src/infer/relate/lattice.rs
+++ b/compiler/rustc_infer/src/infer/relate/lattice.rs
@@ -18,7 +18,6 @@
 //! [lattices]: https://en.wikipedia.org/wiki/Lattice_(order)
 
 use super::combine::ObligationEmittingRelation;
-use crate::infer::type_variable::TypeVariableOrigin;
 use crate::infer::{DefineOpaqueTypes, InferCtxt};
 use crate::traits::ObligationCause;
 
@@ -88,14 +87,12 @@
         // iterate on the subtype obligations that are returned, but I
         // think this suffices. -nmatsakis
         (&ty::Infer(TyVar(..)), _) => {
-            let v = infcx
-                .next_ty_var(TypeVariableOrigin { param_def_id: None, span: this.cause().span });
+            let v = infcx.next_ty_var(this.cause().span);
             this.relate_bound(v, b, a)?;
             Ok(v)
         }
         (_, &ty::Infer(TyVar(..))) => {
-            let v = infcx
-                .next_ty_var(TypeVariableOrigin { param_def_id: None, span: this.cause().span });
+            let v = infcx.next_ty_var(this.cause().span);
             this.relate_bound(v, a, b)?;
             Ok(v)
         }
diff --git a/compiler/rustc_infer/src/infer/relate/lub.rs b/compiler/rustc_infer/src/infer/relate/lub.rs
index 20f5f65..83ab777 100644
--- a/compiler/rustc_infer/src/infer/relate/lub.rs
+++ b/compiler/rustc_infer/src/infer/relate/lub.rs
@@ -140,7 +140,10 @@
         self.fields.param_env
     }
 
-    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
         self.fields.register_predicates(obligations);
     }
 
diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs
index 86a24ee..21064ff 100644
--- a/compiler/rustc_infer/src/infer/relate/type_relating.rs
+++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs
@@ -312,7 +312,10 @@
         self.structurally_relate_aliases
     }
 
-    fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>) {
+    fn register_predicates(
+        &mut self,
+        obligations: impl IntoIterator<Item: ty::Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>>,
+    ) {
         self.fields.register_predicates(obligations);
     }
 
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 758aac0..21ef2e8 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -1,4 +1,5 @@
 use super::{FixupError, FixupResult, InferCtxt};
+use rustc_middle::bug;
 use rustc_middle::ty::fold::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::{self, Const, InferConst, Ty, TyCtxt, TypeFoldable};
@@ -172,84 +173,3 @@
         }
     }
 }
-
-///////////////////////////////////////////////////////////////////////////
-// EAGER RESOLUTION
-
-/// Resolves ty, region, and const vars to their inferred values or their root vars.
-pub struct EagerResolver<'a, 'tcx> {
-    infcx: &'a InferCtxt<'tcx>,
-}
-
-impl<'a, 'tcx> EagerResolver<'a, 'tcx> {
-    pub fn new(infcx: &'a InferCtxt<'tcx>) -> Self {
-        EagerResolver { infcx }
-    }
-}
-
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EagerResolver<'_, 'tcx> {
-    fn interner(&self) -> TyCtxt<'tcx> {
-        self.infcx.tcx
-    }
-
-    fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
-        match *t.kind() {
-            ty::Infer(ty::TyVar(vid)) => match self.infcx.probe_ty_var(vid) {
-                Ok(t) => t.fold_with(self),
-                Err(_) => Ty::new_var(self.infcx.tcx, self.infcx.root_var(vid)),
-            },
-            ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid),
-            ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid),
-            _ => {
-                if t.has_infer() {
-                    t.super_fold_with(self)
-                } else {
-                    t
-                }
-            }
-        }
-    }
-
-    fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
-        match *r {
-            ty::ReVar(vid) => self
-                .infcx
-                .inner
-                .borrow_mut()
-                .unwrap_region_constraints()
-                .opportunistic_resolve_var(self.infcx.tcx, vid),
-            _ => r,
-        }
-    }
-
-    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        match c.kind() {
-            ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
-                // FIXME: we need to fold the ty too, I think.
-                match self.infcx.probe_const_var(vid) {
-                    Ok(c) => c.fold_with(self),
-                    Err(_) => {
-                        ty::Const::new_var(self.infcx.tcx, self.infcx.root_const_var(vid), c.ty())
-                    }
-                }
-            }
-            ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
-                debug_assert_eq!(c.ty(), self.infcx.tcx.types.bool);
-                self.infcx.probe_effect_var(vid).unwrap_or_else(|| {
-                    ty::Const::new_infer(
-                        self.infcx.tcx,
-                        ty::InferConst::EffectVar(self.infcx.root_effect_var(vid)),
-                        self.infcx.tcx.types.bool,
-                    )
-                })
-            }
-            _ => {
-                if c.has_infer() {
-                    c.super_fold_with(self)
-                } else {
-                    c
-                }
-            }
-        }
-    }
-}
diff --git a/compiler/rustc_infer/src/infer/snapshot/fudge.rs b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
index 83667f7..4408251 100644
--- a/compiler/rustc_infer/src/infer/snapshot/fudge.rs
+++ b/compiler/rustc_infer/src/infer/snapshot/fudge.rs
@@ -195,7 +195,7 @@
                     // Recreate it with a fresh variable here.
                     let idx = vid.as_usize() - self.type_vars.0.start.as_usize();
                     let origin = self.type_vars.1[idx];
-                    self.infcx.next_ty_var(origin)
+                    self.infcx.next_ty_var_with_origin(origin)
                 } else {
                     // This variable was created before the
                     // "fudging". Since we refresh all type
@@ -244,7 +244,7 @@
                 // Recreate it with a fresh variable here.
                 let idx = vid.index() - self.const_vars.0.start.index();
                 let origin = self.const_vars.1[idx];
-                self.infcx.next_const_var(ct.ty(), origin)
+                self.infcx.next_const_var_with_origin(ct.ty(), origin)
             } else {
                 ct
             }
diff --git a/compiler/rustc_infer/src/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs
index 96afa25..b56b39e 100644
--- a/compiler/rustc_infer/src/infer/type_variable.rs
+++ b/compiler/rustc_infer/src/infer/type_variable.rs
@@ -1,6 +1,7 @@
 use rustc_data_structures::undo_log::Rollback;
 use rustc_hir::def_id::DefId;
 use rustc_index::IndexVec;
+use rustc_middle::bug;
 use rustc_middle::ty::{self, Ty, TyVid};
 use rustc_span::Span;
 
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 0299af6..28d908a 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -31,8 +31,6 @@
 
 #[macro_use]
 extern crate tracing;
-#[macro_use]
-extern crate rustc_middle;
 
 mod errors;
 pub mod infer;
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index cb067c7..e27e6a0 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -2,7 +2,7 @@
 use crate::traits::Obligation;
 use rustc_hir::def_id::DefId;
 use rustc_macros::extension;
-use rustc_middle::ty::{self, ToPredicate, Ty};
+use rustc_middle::ty::{self, Ty, Upcast};
 
 use super::FulfillmentError;
 use super::{ObligationCause, PredicateObligation};
@@ -26,7 +26,7 @@
                 cause,
                 recursion_depth: 0,
                 param_env,
-                predicate: ty::Binder::dummy(trait_ref).to_predicate(infcx.tcx),
+                predicate: trait_ref.upcast(infcx.tcx),
             },
         );
     }
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index f77a611..0ae4340 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -16,7 +16,7 @@
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::Certainty;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, Const, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Const, Ty, TyCtxt, Upcast};
 use rustc_span::Span;
 
 pub use self::ImplSource::*;
@@ -27,7 +27,7 @@
 pub use self::project::MismatchedProjectionTypes;
 pub(crate) use self::project::UndoLog;
 pub use self::project::{
-    Normalized, NormalizedTy, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey,
+    Normalized, NormalizedTerm, ProjectionCache, ProjectionCacheEntry, ProjectionCacheKey,
     ProjectionCacheStorage, Reveal,
 };
 pub use rustc_middle::traits::*;
@@ -105,7 +105,7 @@
 impl<'tcx> PolyTraitObligation<'tcx> {
     pub fn derived_cause(
         &self,
-        variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
+        variant: impl FnOnce(DerivedCause<'tcx>) -> ObligationCauseCode<'tcx>,
     ) -> ObligationCause<'tcx> {
         self.cause.clone().derived_cause(self.predicate, variant)
     }
@@ -138,10 +138,10 @@
     /// Inherently impossible to fulfill; this trait is implemented if and only
     /// if it is already implemented.
     Cycle(Vec<PredicateObligation<'tcx>>),
-    SelectionError(SelectionError<'tcx>),
-    ProjectionError(MismatchedProjectionTypes<'tcx>),
-    SubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
-    ConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
+    Select(SelectionError<'tcx>),
+    Project(MismatchedProjectionTypes<'tcx>),
+    Subtype(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
+    ConstEquate(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
     Ambiguity {
         /// Overflow is only `Some(suggest_recursion_limit)` when using the next generation
         /// trait solver `-Znext-solver`. With the old solver overflow is eagerly handled by
@@ -155,7 +155,7 @@
         tcx: TyCtxt<'tcx>,
         cause: ObligationCause<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
-        predicate: impl ToPredicate<'tcx, O>,
+        predicate: impl Upcast<TyCtxt<'tcx>, O>,
     ) -> Obligation<'tcx, O> {
         Self::with_depth(tcx, cause, 0, param_env, predicate)
     }
@@ -173,9 +173,9 @@
         cause: ObligationCause<'tcx>,
         recursion_depth: usize,
         param_env: ty::ParamEnv<'tcx>,
-        predicate: impl ToPredicate<'tcx, O>,
+        predicate: impl Upcast<TyCtxt<'tcx>, O>,
     ) -> Obligation<'tcx, O> {
-        let predicate = predicate.to_predicate(tcx);
+        let predicate = predicate.upcast(tcx);
         Obligation { cause, param_env, recursion_depth, predicate }
     }
 
@@ -184,7 +184,7 @@
         span: Span,
         body_id: LocalDefId,
         param_env: ty::ParamEnv<'tcx>,
-        trait_ref: impl ToPredicate<'tcx, O>,
+        trait_ref: impl Upcast<TyCtxt<'tcx>, O>,
     ) -> Obligation<'tcx, O> {
         Obligation::new(tcx, ObligationCause::misc(span, body_id), param_env, trait_ref)
     }
@@ -192,7 +192,7 @@
     pub fn with<P>(
         &self,
         tcx: TyCtxt<'tcx>,
-        value: impl ToPredicate<'tcx, P>,
+        value: impl Upcast<TyCtxt<'tcx>, P>,
     ) -> Obligation<'tcx, P> {
         Obligation::with_depth(tcx, self.cause.clone(), self.recursion_depth, self.param_env, value)
     }
@@ -209,10 +209,10 @@
 
     pub fn is_true_error(&self) -> bool {
         match self.code {
-            FulfillmentErrorCode::SelectionError(_)
-            | FulfillmentErrorCode::ProjectionError(_)
-            | FulfillmentErrorCode::SubtypeError(_, _)
-            | FulfillmentErrorCode::ConstEquateError(_, _) => true,
+            FulfillmentErrorCode::Select(_)
+            | FulfillmentErrorCode::Project(_)
+            | FulfillmentErrorCode::Subtype(_, _)
+            | FulfillmentErrorCode::ConstEquate(_, _) => true,
             FulfillmentErrorCode::Cycle(_) | FulfillmentErrorCode::Ambiguity { overflow: _ } => {
                 false
             }
diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs
index c6ffba5..b696264 100644
--- a/compiler/rustc_infer/src/traits/project.rs
+++ b/compiler/rustc_infer/src/traits/project.rs
@@ -8,7 +8,7 @@
     snapshot_map::{self, SnapshotMapRef, SnapshotMapStorage},
     undo_log::Rollback,
 };
-use rustc_middle::ty::{self, Ty};
+use rustc_middle::ty;
 
 pub use rustc_middle::traits::{EvaluationResult, Reveal};
 
@@ -26,7 +26,7 @@
     pub obligations: Vec<PredicateObligation<'tcx>>,
 }
 
-pub type NormalizedTy<'tcx> = Normalized<'tcx, Ty<'tcx>>;
+pub type NormalizedTerm<'tcx> = Normalized<'tcx, ty::Term<'tcx>>;
 
 impl<'tcx, T> Normalized<'tcx, T> {
     pub fn with<U>(self, value: U) -> Normalized<'tcx, U> {
@@ -77,13 +77,13 @@
 
 #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
 pub struct ProjectionCacheKey<'tcx> {
-    ty: ty::AliasTy<'tcx>,
+    term: ty::AliasTerm<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
 }
 
 impl<'tcx> ProjectionCacheKey<'tcx> {
-    pub fn new(ty: ty::AliasTy<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
-        Self { ty, param_env }
+    pub fn new(term: ty::AliasTerm<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
+        Self { term, param_env }
     }
 }
 
@@ -93,8 +93,8 @@
     Ambiguous,
     Recur,
     Error,
-    NormalizedTy {
-        ty: Normalized<'tcx, ty::Term<'tcx>>,
+    NormalizedTerm {
+        ty: NormalizedTerm<'tcx>,
         /// If we were able to successfully evaluate the
         /// corresponding cache entry key during predicate
         /// evaluation, then this field stores the final
@@ -175,11 +175,7 @@
     }
 
     /// Indicates that `key` was normalized to `value`.
-    pub fn insert_term(
-        &mut self,
-        key: ProjectionCacheKey<'tcx>,
-        value: Normalized<'tcx, ty::Term<'tcx>>,
-    ) {
+    pub fn insert_term(&mut self, key: ProjectionCacheKey<'tcx>, value: NormalizedTerm<'tcx>) {
         debug!(
             "ProjectionCacheEntry::insert_ty: adding cache entry: key={:?}, value={:?}",
             key, value
@@ -190,7 +186,7 @@
             return;
         }
         let fresh_key =
-            map.insert(key, ProjectionCacheEntry::NormalizedTy { ty: value, complete: None });
+            map.insert(key, ProjectionCacheEntry::NormalizedTerm { ty: value, complete: None });
         assert!(!fresh_key, "never started projecting `{key:?}`");
     }
 
@@ -201,13 +197,16 @@
     pub fn complete(&mut self, key: ProjectionCacheKey<'tcx>, result: EvaluationResult) {
         let mut map = self.map();
         match map.get(&key) {
-            Some(ProjectionCacheEntry::NormalizedTy { ty, complete: _ }) => {
+            Some(ProjectionCacheEntry::NormalizedTerm { ty, complete: _ }) => {
                 info!("ProjectionCacheEntry::complete({:?}) - completing {:?}", key, ty);
                 let mut ty = ty.clone();
                 if result.must_apply_considering_regions() {
                     ty.obligations = vec![];
                 }
-                map.insert(key, ProjectionCacheEntry::NormalizedTy { ty, complete: Some(result) });
+                map.insert(
+                    key,
+                    ProjectionCacheEntry::NormalizedTerm { ty, complete: Some(result) },
+                );
             }
             ref value => {
                 // Type inference could "strand behind" old cache entries. Leave
@@ -219,7 +218,7 @@
 
     pub fn is_complete(&mut self, key: ProjectionCacheKey<'tcx>) -> Option<EvaluationResult> {
         self.map().get(&key).and_then(|res| match res {
-            ProjectionCacheEntry::NormalizedTy { ty: _, complete } => *complete,
+            ProjectionCacheEntry::NormalizedTerm { ty: _, complete } => *complete,
             _ => None,
         })
     }
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index 064e09b..b616d37 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -39,12 +39,12 @@
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         use traits::FulfillmentErrorCode::*;
         match *self {
-            SelectionError(ref e) => write!(f, "{e:?}"),
-            ProjectionError(ref e) => write!(f, "{e:?}"),
-            SubtypeError(ref a, ref b) => {
+            Select(ref e) => write!(f, "{e:?}"),
+            Project(ref e) => write!(f, "{e:?}"),
+            Subtype(ref a, ref b) => {
                 write!(f, "CodeSubtypeError({a:?}, {b:?})")
             }
-            ConstEquateError(ref a, ref b) => {
+            ConstEquate(ref a, ref b) => {
                 write!(f, "CodeConstEquateError({a:?}, {b:?})")
             }
             Ambiguity { overflow: None } => write!(f, "Ambiguity"),
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index 6d43011..cc12a4b 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -1,9 +1,9 @@
 use smallvec::smallvec;
 
 use crate::infer::outlives::components::{push_outlives_components, Component};
-use crate::traits::{self, Obligation, PredicateObligation};
+use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation};
 use rustc_data_structures::fx::FxHashSet;
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
@@ -129,7 +129,7 @@
         index: usize,
     ) -> Self {
         let cause = self.cause.clone().derived_cause(parent_trait_pred, |derived| {
-            traits::ImplDerivedObligation(Box::new(traits::ImplDerivedObligationCause {
+            ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause {
                 derived,
                 impl_or_alias_def_id: parent_trait_pred.def_id(),
                 impl_def_predicate_index: Some(index),
@@ -357,9 +357,7 @@
                                 None
                             }
                         })
-                        .map(|clause| {
-                            elaboratable.child(bound_clause.rebind(clause).to_predicate(tcx))
-                        }),
+                        .map(|clause| elaboratable.child(bound_clause.rebind(clause).upcast(tcx))),
                 );
             }
             ty::ClauseKind::RegionOutlives(..) => {
@@ -409,14 +407,14 @@
     tcx: TyCtxt<'tcx>,
     trait_ref: ty::PolyTraitRef<'tcx>,
 ) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
-    elaborate(tcx, [trait_ref.to_predicate(tcx)]).filter_only_self().filter_to_traits()
+    elaborate(tcx, [trait_ref.upcast(tcx)]).filter_only_self().filter_to_traits()
 }
 
 pub fn transitive_bounds<'tcx>(
     tcx: TyCtxt<'tcx>,
     trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
 ) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
-    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx)))
+    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx)))
         .filter_only_self()
         .filter_to_traits()
 }
@@ -431,7 +429,7 @@
     trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
     assoc_name: Ident,
 ) -> FilterToTraits<Elaborator<'tcx, ty::Predicate<'tcx>>> {
-    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.to_predicate(tcx)))
+    elaborate(tcx, trait_refs.map(|trait_ref| trait_ref.upcast(tcx)))
         .filter_only_self_that_defines(assoc_name)
         .filter_to_traits()
 }
@@ -457,7 +455,7 @@
 
     fn next(&mut self) -> Option<ty::PolyTraitRef<'tcx>> {
         while let Some(pred) = self.base_iterator.next() {
-            if let Some(data) = pred.to_opt_poly_trait_pred() {
+            if let Some(data) = pred.as_trait_clause() {
                 return Some(data.map_bound(|t| t.trait_ref));
             }
         }
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 55304bb..d43be6c 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -389,6 +389,7 @@
     let hash_kind = config.opts.unstable_opts.src_hash_algorithm(&target);
 
     util::run_in_thread_pool_with_globals(
+        &early_dcx,
         config.opts.edition,
         config.opts.unstable_opts.threads,
         SourceMapInputs { file_loader, path_mapping, hash_kind },
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index ce4d382..987e48a 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -51,20 +51,38 @@
 pub static STACK_SIZE: OnceLock<usize> = OnceLock::new();
 pub const DEFAULT_STACK_SIZE: usize = 8 * 1024 * 1024;
 
-fn init_stack_size() -> usize {
+fn init_stack_size(early_dcx: &EarlyDiagCtxt) -> usize {
     // Obey the environment setting or default
     *STACK_SIZE.get_or_init(|| {
         env::var_os("RUST_MIN_STACK")
-            .map(|os_str| os_str.to_string_lossy().into_owned())
-            // ignore if it is set to nothing
-            .filter(|s| s.trim() != "")
-            .map(|s| s.trim().parse::<usize>().unwrap())
+            .as_ref()
+            .map(|os_str| os_str.to_string_lossy())
+            // if someone finds out `export RUST_MIN_STACK=640000` isn't enough stack
+            // they might try to "unset" it by running `RUST_MIN_STACK=  rustc code.rs`
+            // this is wrong, but std would nonetheless "do what they mean", so let's do likewise
+            .filter(|s| !s.trim().is_empty())
+            // rustc is a batch program, so error early on inputs which are unlikely to be intended
+            // so no one thinks we parsed them setting `RUST_MIN_STACK="64 megabytes"`
+            // FIXME: we could accept `RUST_MIN_STACK=64MB`, perhaps?
+            .map(|s| {
+                let s = s.trim();
+                // FIXME(workingjubilee): add proper diagnostics when we factor out "pre-run" setup
+                #[allow(rustc::untranslatable_diagnostic, rustc::diagnostic_outside_of_impl)]
+                s.parse::<usize>().unwrap_or_else(|_| {
+                    let mut err = early_dcx.early_struct_fatal(format!(
+                        r#"`RUST_MIN_STACK` should be a number of bytes, but was "{s}""#,
+                    ));
+                    err.note("you can also unset `RUST_MIN_STACK` to use the default stack size");
+                    err.emit()
+                })
+            })
             // otherwise pick a consistent default
             .unwrap_or(DEFAULT_STACK_SIZE)
     })
 }
 
 fn run_in_thread_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
+    thread_stack_size: usize,
     edition: Edition,
     sm_inputs: SourceMapInputs,
     f: F,
@@ -75,7 +93,7 @@
     // the parallel compiler, in particular to ensure there is no accidental
     // sharing of data between the main thread and the compilation thread
     // (which might cause problems for the parallel compiler).
-    let builder = thread::Builder::new().name("rustc".to_string()).stack_size(init_stack_size());
+    let builder = thread::Builder::new().name("rustc".to_string()).stack_size(thread_stack_size);
 
     // We build the session globals and run `f` on the spawned thread, because
     // `SessionGlobals` does not impl `Send` in the non-parallel compiler.
@@ -100,16 +118,19 @@
 
 #[cfg(not(parallel_compiler))]
 pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
+    thread_builder_diag: &EarlyDiagCtxt,
     edition: Edition,
     _threads: usize,
     sm_inputs: SourceMapInputs,
     f: F,
 ) -> R {
-    run_in_thread_with_globals(edition, sm_inputs, f)
+    let thread_stack_size = init_stack_size(thread_builder_diag);
+    run_in_thread_with_globals(thread_stack_size, edition, sm_inputs, f)
 }
 
 #[cfg(parallel_compiler)]
 pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce(CurrentGcx) -> R + Send, R: Send>(
+    thread_builder_diag: &EarlyDiagCtxt,
     edition: Edition,
     threads: usize,
     sm_inputs: SourceMapInputs,
@@ -121,10 +142,12 @@
     use rustc_query_system::query::{break_query_cycles, QueryContext};
     use std::process;
 
+    let thread_stack_size = init_stack_size(thread_builder_diag);
+
     let registry = sync::Registry::new(std::num::NonZero::new(threads).unwrap());
 
     if !sync::is_dyn_thread_safe() {
-        return run_in_thread_with_globals(edition, sm_inputs, |current_gcx| {
+        return run_in_thread_with_globals(thread_stack_size, edition, sm_inputs, |current_gcx| {
             // Register the thread for use with the `WorkerLocal` type.
             registry.register();
 
@@ -167,7 +190,7 @@
                 })
                 .unwrap();
         })
-        .stack_size(init_stack_size());
+        .stack_size(thread_stack_size);
 
     // We create the session globals on the main thread, then create the thread
     // pool. Upon creation, each worker thread created gets a copy of the
@@ -376,31 +399,17 @@
 
                 if let ast::MetaItemKind::NameValue(spanned) = a.meta_kind().unwrap() {
                     let span = spanned.span;
-                    let lev_candidate = find_best_match_for_name(
+                    let candidate = find_best_match_for_name(
                         &CRATE_TYPES.iter().map(|(k, _)| *k).collect::<Vec<_>>(),
                         n,
                         None,
                     );
-                    if let Some(candidate) = lev_candidate {
-                        lint_buffer.buffer_lint_with_diagnostic(
-                            lint::builtin::UNKNOWN_CRATE_TYPES,
-                            ast::CRATE_NODE_ID,
-                            span,
-                            "invalid `crate_type` value",
-                            BuiltinLintDiag::UnknownCrateTypes(
-                                span,
-                                "did you mean".to_string(),
-                                format!("\"{candidate}\""),
-                            ),
-                        );
-                    } else {
-                        lint_buffer.buffer_lint(
-                            lint::builtin::UNKNOWN_CRATE_TYPES,
-                            ast::CRATE_NODE_ID,
-                            span,
-                            "invalid `crate_type` value",
-                        );
-                    }
+                    lint_buffer.buffer_lint(
+                        lint::builtin::UNKNOWN_CRATE_TYPES,
+                        ast::CRATE_NODE_ID,
+                        span,
+                        BuiltinLintDiag::UnknownCrateTypes { span, candidate },
+                    );
                 }
             } else {
                 // This is here mainly to check for using a macro, such as
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index 676a7c2..6f6480a 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -1,13 +1,19 @@
+lint_abs_path_with_module = absolute paths must start with `self`, `super`, `crate`, or an external crate name in the 2018 edition
+    .suggestion = use `crate`
+
+lint_ambiguous_glob_reexport = ambiguous glob re-exports
+    .label_first_reexport = the name `{$name}` in the {$namespace} namespace is first re-exported here
+    .label_duplicate_reexport = but the name `{$name}` in the {$namespace} namespace is also re-exported here
+
 lint_ambiguous_wide_pointer_comparisons = ambiguous wide pointer comparison, the comparison includes metadata which may not be expected
     .addr_metadata_suggestion = use explicit `std::ptr::eq` method to compare metadata and addresses
     .addr_suggestion = use `std::ptr::addr_eq` or untyped pointers to only compare their addresses
 
-lint_array_into_iter =
-    this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <{$target} as IntoIterator>::into_iter in Rust 2021
-    .use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity
-    .remove_into_iter_suggestion = or remove `.into_iter()` to iterate by value
-    .use_explicit_into_iter_suggestion =
-        or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
+lint_associated_const_elided_lifetime = {$elided ->
+        [true] `&` without an explicit lifetime name cannot be used here
+        *[false] `'_` cannot be used here
+    }
+    .suggestion = use the `'static` lifetime
 
 lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified
     .note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future`
@@ -26,10 +32,19 @@
 lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering
     .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed`
 
+lint_avoid_att_syntax =
+    avoid using `.att_syntax`, prefer using `options(att_syntax)` instead
+
+lint_avoid_intel_syntax =
+    avoid using `.intel_syntax`, Intel syntax is the default
+
 lint_bad_attribute_argument = bad attribute argument
 
 lint_bad_opt_access = {$msg}
 
+lint_break_with_label_and_loop = this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression
+    .suggestion = wrap this expression in parentheses
+
 lint_builtin_allow_internal_unsafe =
     `allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site
 
@@ -37,6 +52,8 @@
     .suggestion = try naming the parameter or explicitly ignoring it
 
 lint_builtin_asm_labels = avoid using named labels in inline assembly
+    .help = only local labels of the form `<number>:` should be used in inline asm
+    .note = see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information
 
 lint_builtin_box_pointers = type uses owned (Box type) pointers: {$ty}
 
@@ -161,6 +178,12 @@
 lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
     .suggestion = use `loop`
 
+lint_byte_slice_in_packed_struct_with_derive = {$ty} slice in a packed struct that derives a built-in trait
+    .help = consider implementing the trait by hand, or remove the `packed` attribute
+
+lint_cfg_attr_no_attributes =
+    `#[cfg_attr]` does not expand to any attributes
+
 lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
 
 lint_command_line_source = `forbid` lint level was set on command line
@@ -169,12 +192,20 @@
     .current_use = this identifier can be confused with `{$existing_sym}`
     .other_use = other identifier used here
 
+lint_crate_name_in_cfg_attr_deprecated =
+    `crate_name` within an `#![cfg_attr]` attribute is deprecated
+
+lint_crate_type_in_cfg_attr_deprecated =
+    `crate_type` within an `#![cfg_attr]` attribute is deprecated
+
 lint_cstring_ptr = getting the inner pointer of a temporary `CString`
     .as_ptr_label = this pointer will be invalid
     .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
     .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
     .help = for more information, see https://doc.rust-lang.org/reference/destructors.html
 
+lint_custom_inner_attribute_unstable = custom inner attributes are unstable
+
 lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
     .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
 
@@ -185,6 +216,11 @@
     .suggestion = change it to
     .help = change it to {$replace}
 
+lint_deprecated_where_clause_location = where clause not allowed here
+    .note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+    .suggestion_move_to_end = move it to the end of the type declaration
+    .suggestion_remove_where = remove this `where`
+
 lint_diag_out_of_impl =
     diagnostics should only be created in `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls
 
@@ -202,6 +238,11 @@
     .label = argument has type `{$arg_ty}`
     .note = use `let _ = ...` to ignore the expression or result
 
+lint_duplicate_macro_attribute =
+    duplicated attribute
+
+lint_duplicate_matcher_binding = duplicate matcher binding
+
 lint_enum_intrinsics_mem_discriminant =
     the return value of `mem::discriminant` is unspecified when called with a non-enum type
     .note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum.
@@ -214,6 +255,13 @@
     .note = the `unfulfilled_lint_expectations` lint can't be expected and will always produce this message
     .rationale = {$rationale}
 
+lint_extern_crate_not_idiomatic = `extern crate` is not idiomatic in the new edition
+    .suggestion = convert it to a `use`
+
+lint_extern_without_abi = extern declarations without an explicit ABI are deprecated
+    .label = ABI should be specified here
+    .help = the default ABI is {$default_abi}
+
 lint_for_loops_over_fallibles =
     for loop over {$article} `{$ty}`. This is more readably written as an `if let` statement
     .suggestion = consider using `if let` to clear intent
@@ -228,6 +276,12 @@
     .label = argument has type `{$arg_ty}`
     .note = use `let _ = ...` to ignore the expression or result
 
+lint_hidden_glob_reexport = private item shadows public glob re-export
+    .note_glob_reexport = the name `{$name}` in the {$namespace} namespace is supposed to be publicly re-exported here
+    .note_private_item = but the private item here shadows it
+
+lint_hidden_lifetime_parameters = hidden lifetime parameters in types are deprecated
+
 lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label}
     .label = this {$label} contains {$count ->
         [one] an invisible
@@ -269,6 +323,22 @@
 
 lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level
 
+lint_ill_formed_attribute_input = {$num_suggestions ->
+        [1] attribute must be of the form {$suggestions}
+        *[other] valid forms for the attribute are {$suggestions}
+    }
+
+lint_impl_trait_overcaptures = `{$self_ty}` will capture more lifetimes than possibly intended in edition 2024
+    .note = specifically, {$num_captured ->
+        [one] this lifetime is
+        *[other] these lifetimes are
+     } in scope but not mentioned in the type's bounds
+    .note2 = all lifetimes in scope will be captured by `impl Trait`s in edition 2024
+    .suggestion = use the precise capturing `use<...>` syntax to make the captures explicit
+
+lint_impl_trait_redundant_captures = all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
+    .suggestion = remove the `use<...>` syntax
+
 lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe
     .label = not FFI-safe
     .note = the type is defined here
@@ -328,6 +398,14 @@
 lint_improper_ctypes_union_layout_reason = this union has unspecified layout
 lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
 
+lint_incomplete_include =
+    include macro expected single expression in source
+
+lint_inner_macro_attribute_unstable = inner macro attributes are unstable
+
+lint_invalid_crate_type_value = invalid `crate_type` value
+    .suggestion = did you mean
+
 # FIXME: we should ordinalize $valid_up_to when we add support for doing so
 lint_invalid_from_utf8_checked = calls to `{$method}` with a invalid literal always return an error
     .label = the literal was valid UTF-8 up to the {$valid_up_to} bytes
@@ -356,9 +434,22 @@
 
 lint_invalid_reference_casting_note_ty_has_interior_mutability = even for types with interior mutability, the only legal way to obtain a mutable pointer from a shared reference is through `UnsafeCell::get`
 
+lint_legacy_derive_helpers = derive helper attribute is used before it is introduced
+    .label = the attribute is introduced here
+
 lint_lintpass_by_hand = implementing `LintPass` by hand
     .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
 
+lint_macro_expanded_macro_exports_accessed_by_absolute_paths = macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
+    .note = the macro is defined here
+
+lint_macro_is_private = macro `{$ident}` is private
+
+lint_macro_rule_never_used = rule #{$n} of macro `{$name}` is never used
+
+lint_macro_use_deprecated =
+    deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead
+
 lint_malformed_attribute = malformed lint attribute input
 
 lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
@@ -368,6 +459,12 @@
     .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
     .suggestion = you might have meant to use `Iterator::for_each`
 
+lint_metavariable_still_repeating = variable '{$name}' is still repeating at this depth
+
+lint_metavariable_wrong_operator = meta-variable repeats with different Kleene operator
+
+lint_missing_fragment_specifier = missing fragment specifier
+
 lint_mixed_script_confusables =
     the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables
     .includes_note = the usage includes {$includes}
@@ -375,6 +472,11 @@
 
 lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits
 
+lint_named_argument_used_positionally = named argument `{$named_arg_name}` is not used by name
+    .label_named_arg = this named argument is referred to by position in formatting string
+    .label_position_arg = this formatting argument uses named argument `{$named_arg_name}` by position
+    .suggestion = use the named argument by name to avoid ambiguity
+
 lint_node_source = `forbid` level set here
     .note = {$reason}
 
@@ -486,6 +588,9 @@
 
 lint_opaque_hidden_inferred_bound_sugg = add this bound
 
+lint_or_patterns_back_compat = the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro
+    .suggestion = use pat_param to preserve semantics
+
 lint_overflowing_bin_hex = literal out of range for `{$ty}`
     .negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}`
     .negative_becomes_note = and the value `-{$lit}` will become `{$actually}{$ty}`
@@ -515,6 +620,21 @@
 
 lint_path_statement_no_effect = path statement with no effect
 
+lint_pattern_in_bodiless = patterns aren't allowed in functions without bodies
+    .label = pattern not allowed in function without body
+
+lint_pattern_in_foreign = patterns aren't allowed in foreign function declarations
+    .label = pattern not allowed in foreign function
+
+lint_private_extern_crate_reexport =
+    extern crate `{$ident}` is private, and cannot be re-exported (error E0365), consider declaring with `pub`
+
+lint_proc_macro_back_compat = using an old version of `{$crate_name}`
+    .note = older versions of the `{$crate_name}` crate will stop compiling in future versions of Rust; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives
+
+lint_proc_macro_derive_resolution_fallback = cannot find {$ns} `{$ident}` in this scope
+    .label = names from parent modules are not accessible without an explicit import
+
 lint_ptr_null_checks_fn_ptr = function pointers are not nullable, so checking them for null will always return false
     .help = wrap the function pointer inside an `Option` and use `Option::is_none` to check for null pointer value
     .label = expression has type `{$orig_ty}`
@@ -536,6 +656,16 @@
 
 lint_reason_must_come_last = reason in lint attribute must come last
 
+lint_redundant_import = the item `{$ident}` is imported redundantly
+    .label_imported_here = the item `{ident}` is already imported here
+    .label_defined_here = the item `{ident}` is already defined here
+    .label_imported_prelude = the item `{ident}` is already imported by the extern prelude
+    .label_defined_prelude = the item `{ident}` is already defined by the extern prelude
+
+lint_redundant_import_visibility = glob import doesn't reexport anything with visibility `{$import_vis}` because no imported item is public enough
+    .note = the most public imported item is `{$max_vis}`
+    .help = reduce the glob import's visibility or increase visibility of imported items
+
 lint_redundant_semicolons =
     unnecessary trailing {$multiple ->
         [true] semicolons
@@ -546,6 +676,8 @@
         *[false] this semicolon
     }
 
+lint_remove_mut_from_pattern = remove `mut` from the parameter
+
 lint_removed_lint = lint `{$name}` has been removed: {$reason}
 
 lint_renamed_lint = lint `{$name}` has been renamed to `{$replace}`
@@ -554,6 +686,22 @@
 
 lint_requested_level = requested on the command line with `{$level} {$lint_name}`
 
+lint_reserved_prefix = prefix `{$prefix}` is unknown
+    .label = unknown prefix
+    .suggestion = insert whitespace here to avoid this being parsed as a prefix in Rust 2021
+
+lint_shadowed_into_iter =
+    this method call resolves to `<&{$target} as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<{$target} as IntoIterator>::into_iter` in Rust {$edition}
+    .use_iter_suggestion = use `.iter()` instead of `.into_iter()` to avoid ambiguity
+    .remove_into_iter_suggestion = or remove `.into_iter()` to iterate by value
+    .use_explicit_into_iter_suggestion =
+        or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
+
+lint_single_use_lifetime = lifetime parameter `{$ident}` only used once
+    .label_param = this lifetime...
+    .label_use = ...is used only here
+    .suggestion = elide the single-use lifetime
+
 lint_span_use_eq_ctxt = use `.eq_ctxt()` instead of `.ctxt() == .ctxt()`
 
 lint_supertrait_as_deref_target = this `Deref` implementation is covered by an implicit supertrait coercion
@@ -567,6 +715,10 @@
 lint_suspicious_double_ref_deref =
     using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type
 
+lint_trailing_semi_macro = trailing semicolon in macro used in expression position
+    .note1 = macro invocations at the end of a block are treated as expressions
+    .note2 = to ignore the value produced by the macro, add a semicolon after the invocation of `{$name}`
+
 lint_ty_qualified = usage of qualified `ty::{$ty}`
     .suggestion = try importing it and using it unqualified
 
@@ -580,12 +732,64 @@
     .label = argument has type `{$arg_ty}`
     .suggestion = use `std::mem::ManuallyDrop::into_inner` to get the inner value
 
+lint_unexpected_cfg_add_build_rs_println = or consider adding `{$build_rs_println}` to the top of the `build.rs`
+lint_unexpected_cfg_add_cargo_feature = consider using a Cargo feature instead
+lint_unexpected_cfg_add_cargo_toml_lint_cfg = or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:{$cargo_toml_lint_cfg}
+lint_unexpected_cfg_add_cmdline_arg = to expect this configuration use `{$cmdline_arg}`
+lint_unexpected_cfg_define_features = consider defining some features in `Cargo.toml`
+lint_unexpected_cfg_doc_cargo = see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
+lint_unexpected_cfg_doc_rustc = see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
+
+lint_unexpected_cfg_name = unexpected `cfg` condition name: `{$name}`
+lint_unexpected_cfg_name_expected_names = expected names are: {$possibilities}{$and_more ->
+        [0] {""}
+        *[other] {" "}and {$and_more} more
+    }
+lint_unexpected_cfg_name_expected_values = expected values for `{$best_match}` are: {$possibilities}
+lint_unexpected_cfg_name_similar_name = there is a config with a similar name
+lint_unexpected_cfg_name_similar_name_different_values = there is a config with a similar name and different values
+lint_unexpected_cfg_name_similar_name_no_value = there is a config with a similar name and no value
+lint_unexpected_cfg_name_similar_name_value = there is a config with a similar name and value
+lint_unexpected_cfg_name_with_similar_value = found config with similar value
+
+lint_unexpected_cfg_value = unexpected `cfg` condition value: {$has_value ->
+        [true] `{$value}`
+        *[false] (none)
+    }
+lint_unexpected_cfg_value_add_feature = consider adding `{$value}` as a feature in `Cargo.toml`
+lint_unexpected_cfg_value_expected_values = expected values for `{$name}` are: {$have_none_possibility ->
+        [true] {"(none), "}
+        *[false] {""}
+    }{$possibilities}{$and_more ->
+        [0] {""}
+        *[other] {" "}and {$and_more} more
+    }
+lint_unexpected_cfg_value_no_expected_value = no expected value for `{$name}`
+lint_unexpected_cfg_value_no_expected_values = no expected values for `{$name}`
+lint_unexpected_cfg_value_remove_condition = remove the condition
+lint_unexpected_cfg_value_remove_value = remove the value
+lint_unexpected_cfg_value_similar_name = there is a expected value with a similar name
+lint_unexpected_cfg_value_specify_value = specify a config value
+
 lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op
      .label = this function will not propagate the caller location
 
+lint_unicode_text_flow = unicode codepoint changing visible direction of text present in comment
+    .label = {$num_codepoints ->
+            [1] this comment contains an invisible unicode text flow control codepoint
+            *[other] this comment contains invisible unicode text flow control codepoints
+        }
+    .note = these kind of unicode codepoints change the way text flows on applications that support them, but can cause confusion because they change the order of characters on the screen
+    .suggestion = if their presence wasn't intentional, you can remove them
+    .label_comment_char = {$c_debug}
+
+
 lint_unit_bindings = binding has unit type `()`
     .label = this pattern is inferred to be the unit type `()`
 
+lint_unknown_diagnostic_attribute = unknown diagnostic attribute
+lint_unknown_diagnostic_attribute_typo_sugg = an attribute with a similar name exists
+
 lint_unknown_gated_lint =
     unknown lint: `{$name}`
     .note = the `{$name}` lint is unstable
@@ -601,9 +805,16 @@
         *[false] did you mean: `{$replace}`
     }
 
+lint_unknown_macro_variable = unknown macro variable `{$name}`
+
 lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
     .help = add `#![register_tool({$tool_name})]` to the crate root
 
+lint_unnameable_test_items = cannot test inner items
+
+lint_unnecessary_qualification = unnecessary qualification
+    .suggestion = remove the unnecessary path segments
+
 lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
 
 lint_untranslatable_diag = diagnostics should be created using translatable messages
@@ -611,6 +822,9 @@
 lint_unused_allocation = unnecessary allocation, use `&` instead
 lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead
 
+lint_unused_builtin_attribute = unused attribute `{$attr_name}`
+    .note = the built-in attribute `{$attr_name}` will be ignored, since it's applied to the macro invocation `{$macro_name}`
+
 lint_unused_closure =
     unused {$pre}{$count ->
         [one] closure
@@ -627,14 +841,43 @@
     }{$post} that must be used
     .note = coroutines are lazy and do nothing unless resumed
 
+lint_unused_crate_dependency = external crate `{$extern_crate}` unused in `{$local_crate}`: remove the dependency or add `use {$extern_crate} as _;`
+
 lint_unused_def = unused {$pre}`{$def}`{$post} that must be used
     .suggestion = use `let _ = ...` to ignore the resulting value
 
 lint_unused_delim = unnecessary {$delim} around {$item}
     .suggestion = remove these {$delim}
 
+lint_unused_doc_comment = unused doc comment
+    .label = rustdoc does not generate documentation for macro invocations
+    .help = to document an item produced by a macro, the macro must produce the documentation as part of its expansion
+
+lint_unused_extern_crate = unused extern crate
+    .suggestion = remove it
+
 lint_unused_import_braces = braces around {$node} is unnecessary
 
+lint_unused_imports = {$num_snippets ->
+        [one] unused import: {$span_snippets}
+        *[other] unused imports: {$span_snippets}
+    }
+    .suggestion_remove_whole_use = remove the whole `use` item
+    .suggestion_remove_imports = {$num_to_remove ->
+            [one] remove the unused import
+            *[other] remove the unused imports
+        }
+    .help = if this is a test module, consider adding a `#[cfg(test)]` to the containing module
+
+lint_unused_label = unused label
+
+lint_unused_lifetime = lifetime parameter `{$ident}` never used
+    .suggestion = elide the unused lifetime
+
+lint_unused_macro_definition = unused macro definition: `{$name}`
+
+lint_unused_macro_use = unused `#[macro_use]` import
+
 lint_unused_op = unused {$op} that must be used
     .label = the {$op} produces a value
     .suggestion = use `let _ = ...` to ignore the resulting value
@@ -643,3 +886,6 @@
 
 lint_variant_size_differences =
     enum variant is more than three times larger ({$largest} bytes) than the next largest
+
+lint_wasm_c_abi =
+    older versions of the `wasm-bindgen` crate will be incompatible with future versions of Rust; please update to `wasm-bindgen` v0.2.88
diff --git a/compiler/rustc_lint/src/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs
deleted file mode 100644
index 8f4bae3..0000000
--- a/compiler/rustc_lint/src/array_into_iter.rs
+++ /dev/null
@@ -1,144 +0,0 @@
-use crate::{
-    lints::{ArrayIntoIterDiag, ArrayIntoIterDiagSub},
-    LateContext, LateLintPass, LintContext,
-};
-use rustc_hir as hir;
-use rustc_middle::bug;
-use rustc_middle::ty;
-use rustc_middle::ty::adjustment::{Adjust, Adjustment};
-use rustc_session::lint::FutureIncompatibilityReason;
-use rustc_session::{declare_lint, impl_lint_pass};
-use rustc_span::edition::Edition;
-use rustc_span::symbol::sym;
-use rustc_span::Span;
-
-declare_lint! {
-    /// The `array_into_iter` lint detects calling `into_iter` on arrays.
-    ///
-    /// ### Example
-    ///
-    /// ```rust,edition2018
-    /// # #![allow(unused)]
-    /// [1, 2, 3].into_iter().for_each(|n| { *n; });
-    /// ```
-    ///
-    /// {{produces}}
-    ///
-    /// ### Explanation
-    ///
-    /// Since Rust 1.53, arrays implement `IntoIterator`. However, to avoid
-    /// breakage, `array.into_iter()` in Rust 2015 and 2018 code will still
-    /// behave as `(&array).into_iter()`, returning an iterator over
-    /// references, just like in Rust 1.52 and earlier.
-    /// This only applies to the method call syntax `array.into_iter()`, not to
-    /// any other syntax such as `for _ in array` or `IntoIterator::into_iter(array)`.
-    pub ARRAY_INTO_ITER,
-    Warn,
-    "detects calling `into_iter` on arrays in Rust 2015 and 2018",
-    @future_incompatible = FutureIncompatibleInfo {
-        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021),
-        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
-    };
-}
-
-#[derive(Copy, Clone, Default)]
-pub struct ArrayIntoIter {
-    for_expr_span: Span,
-}
-
-impl_lint_pass!(ArrayIntoIter => [ARRAY_INTO_ITER]);
-
-impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter {
-    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
-        // Save the span of expressions in `for _ in expr` syntax,
-        // so we can give a better suggestion for those later.
-        if let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) = &expr.kind {
-            if let hir::ExprKind::Call(path, [arg]) = &arg.kind {
-                if let hir::ExprKind::Path(hir::QPath::LangItem(
-                    hir::LangItem::IntoIterIntoIter,
-                    ..,
-                )) = &path.kind
-                {
-                    self.for_expr_span = arg.span;
-                }
-            }
-        }
-
-        // We only care about method call expressions.
-        if let hir::ExprKind::MethodCall(call, receiver_arg, ..) = &expr.kind {
-            if call.ident.name != sym::into_iter {
-                return;
-            }
-
-            // Check if the method call actually calls the libcore
-            // `IntoIterator::into_iter`.
-            let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
-            match cx.tcx.trait_of_item(def_id) {
-                Some(trait_id) if cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_id) => {}
-                _ => return,
-            };
-
-            // As this is a method call expression, we have at least one argument.
-            let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
-            let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
-
-            let Some(Adjustment { kind: Adjust::Borrow(_), target }) = adjustments.last() else {
-                return;
-            };
-
-            let types =
-                std::iter::once(receiver_ty).chain(adjustments.iter().map(|adj| adj.target));
-
-            let mut found_array = false;
-
-            for ty in types {
-                match ty.kind() {
-                    // If we run into a &[T; N] or &[T] first, there's nothing to warn about.
-                    // It'll resolve to the reference version.
-                    ty::Ref(_, inner_ty, _) if inner_ty.is_array() => return,
-                    ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => return,
-                    // Found an actual array type without matching a &[T; N] first.
-                    // This is the problematic case.
-                    ty::Array(..) => {
-                        found_array = true;
-                        break;
-                    }
-                    _ => {}
-                }
-            }
-
-            if !found_array {
-                return;
-            }
-
-            // Emit lint diagnostic.
-            let target = match *target.kind() {
-                ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]",
-                ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]",
-                // We know the original first argument type is an array type,
-                // we know that the first adjustment was an autoref coercion
-                // and we know that `IntoIterator` is the trait involved. The
-                // array cannot be coerced to something other than a reference
-                // to an array or to a slice.
-                _ => bug!("array type coerced to something other than array or slice"),
-            };
-            let sub = if self.for_expr_span == expr.span {
-                Some(ArrayIntoIterDiagSub::RemoveIntoIter {
-                    span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
-                })
-            } else if receiver_ty.is_array() {
-                Some(ArrayIntoIterDiagSub::UseExplicitIntoIter {
-                    start_span: expr.span.shrink_to_lo(),
-                    end_span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
-                })
-            } else {
-                None
-            };
-            cx.emit_span_lint(
-                ARRAY_INTO_ITER,
-                call.ident.span,
-                ArrayIntoIterDiag { target, suggestion: call.ident.span, sub },
-            );
-        }
-    }
-}
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index ba316e5..0f059bc 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -30,16 +30,17 @@
         BuiltinExplicitOutlivesSuggestion, BuiltinFeatureIssueNote, BuiltinIncompleteFeatures,
         BuiltinIncompleteFeaturesHelp, BuiltinInternalFeatures, BuiltinKeywordIdents,
         BuiltinMissingCopyImpl, BuiltinMissingDebugImpl, BuiltinMissingDoc,
-        BuiltinMutablesTransmutes, BuiltinNoMangleGeneric, BuiltinNonShorthandFieldPatterns,
-        BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds, BuiltinTypeAliasGenericBounds,
-        BuiltinTypeAliasGenericBoundsSuggestion, BuiltinTypeAliasWhereClause,
-        BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
+        BuiltinMutablesTransmutes, BuiltinNamedAsmLabel, BuiltinNoMangleGeneric,
+        BuiltinNonShorthandFieldPatterns, BuiltinSpecialModuleNameUsed, BuiltinTrivialBounds,
+        BuiltinTypeAliasGenericBounds, BuiltinTypeAliasGenericBoundsSuggestion,
+        BuiltinTypeAliasWhereClause, BuiltinUngatedAsyncFnTrackCaller, BuiltinUnpermittedTypeInit,
         BuiltinUnpermittedTypeInitSub, BuiltinUnreachablePub, BuiltinUnsafe,
         BuiltinUnstableFeatures, BuiltinUnusedDocComment, BuiltinUnusedDocCommentSub,
         BuiltinWhileTrue, SuggestChangingAssocTypes,
     },
     EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level, LintContext,
 };
+use ast::token::TokenKind;
 use rustc_ast::tokenstream::{TokenStream, TokenTree};
 use rustc_ast::visit::{FnCtxt, FnKind};
 use rustc_ast::{self as ast, *};
@@ -56,10 +57,10 @@
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::GenericArgKind;
-use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::TypeVisitableExt;
+use rustc_middle::ty::Upcast;
 use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
-use rustc_session::lint::{BuiltinLintDiag, FutureIncompatibilityReason};
+use rustc_session::lint::FutureIncompatibilityReason;
 use rustc_session::{declare_lint, declare_lint_pass, impl_lint_pass};
 use rustc_span::edition::Edition;
 use rustc_span::source_map::Spanned;
@@ -359,11 +360,11 @@
 
     fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) {
         match it.kind {
-            ast::ItemKind::Trait(box ast::Trait { unsafety: ast::Unsafe::Yes(_), .. }) => {
+            ast::ItemKind::Trait(box ast::Trait { safety: ast::Safety::Unsafe(_), .. }) => {
                 self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeTrait);
             }
 
-            ast::ItemKind::Impl(box ast::Impl { unsafety: ast::Unsafe::Yes(_), .. }) => {
+            ast::ItemKind::Impl(box ast::Impl { safety: ast::Safety::Unsafe(_), .. }) => {
                 self.report_unsafe(cx, it.span, BuiltinUnsafe::UnsafeImpl);
             }
 
@@ -418,7 +419,7 @@
         if let FnKind::Fn(
             ctxt,
             _,
-            ast::FnSig { header: ast::FnHeader { unsafety: ast::Unsafe::Yes(_), .. }, .. },
+            ast::FnSig { header: ast::FnHeader { safety: ast::Safety::Unsafe(_), .. }, .. },
             _,
             _,
             body,
@@ -733,7 +734,7 @@
         cause: traits::ObligationCause::dummy(),
         param_env,
         recursion_depth: 0,
-        predicate: ty::Binder::dummy(pred).to_predicate(tcx),
+        predicate: pred.upcast(tcx),
     };
 
     tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation)
@@ -1869,16 +1870,24 @@
 
 impl KeywordIdents {
     fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: &TokenStream) {
+        // Check if the preceding token is `$`, because we want to allow `$async`, etc.
+        let mut prev_dollar = false;
         for tt in tokens.trees() {
             match tt {
                 // Only report non-raw idents.
                 TokenTree::Token(token, _) => {
                     if let Some((ident, token::IdentIsRaw::No)) = token.ident() {
-                        self.check_ident_token(cx, UnderMacro(true), ident);
+                        if !prev_dollar {
+                            self.check_ident_token(cx, UnderMacro(true), ident);
+                        }
+                    } else if token.kind == TokenKind::Dollar {
+                        prev_dollar = true;
+                        continue;
                     }
                 }
                 TokenTree::Delimited(.., tts) => self.check_tokens(cx, tts),
             }
+            prev_dollar = false;
         }
     }
 
@@ -2873,16 +2882,7 @@
                     let target_spans: MultiSpan =
                         if spans.len() > 0 { spans.into() } else { (*template_span).into() };
 
-                    cx.span_lint_with_diagnostics(
-                            NAMED_ASM_LABELS,
-                            Some(target_spans),
-                            fluent::lint_builtin_asm_labels,
-                            |_| {},
-                            BuiltinLintDiag::NamedAsmLabel(
-                                "only local labels of the form `<number>:` should be used in inline asm"
-                                    .to_string(),
-                            ),
-                        );
+                    cx.emit_span_lint(NAMED_ASM_LABELS, target_spans, BuiltinNamedAsmLabel);
                 }
             }
         }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 0931bb2..deeb3ae 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -30,7 +30,7 @@
 use rustc_middle::bug;
 use rustc_middle::middle::privacy::EffectiveVisibilities;
 use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
-use rustc_middle::ty::print::{with_no_trimmed_paths, PrintError};
+use rustc_middle::ty::print::{with_no_trimmed_paths, PrintError, PrintTraitRefExt as _};
 use rustc_middle::ty::{self, print::Printer, GenericArg, RegisteredTools, Ty, TyCtxt};
 use rustc_session::lint::{BuiltinLintDiag, LintExpectationId};
 use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
@@ -527,30 +527,24 @@
     pub buffered: LintBuffer,
 }
 
-pub trait LintContext {
-    fn sess(&self) -> &Session;
-
+impl EarlyContext<'_> {
     /// Emit a lint at the appropriate level, with an optional associated span and an existing
     /// diagnostic.
     ///
     /// [`lint_level`]: rustc_middle::lint::lint_level#decorate-signature
     #[rustc_lint_diagnostics]
-    fn span_lint_with_diagnostics(
+    pub fn span_lint_with_diagnostics(
         &self,
         lint: &'static Lint,
-        span: Option<impl Into<MultiSpan>>,
-        msg: impl Into<DiagMessage>,
-        decorate: impl for<'a, 'b> FnOnce(&'b mut Diag<'a, ()>),
+        span: MultiSpan,
         diagnostic: BuiltinLintDiag,
     ) {
-        // We first generate a blank diagnostic.
-        self.opt_span_lint(lint, span, msg, |db| {
-            // Now, set up surrounding context.
-            diagnostics::builtin(self.sess(), diagnostic, db);
-            // Rewrap `db`, and pass control to the user.
-            decorate(db)
-        });
+        diagnostics::emit_buffered_lint(self, lint, span, diagnostic)
     }
+}
+
+pub trait LintContext {
+    fn sess(&self) -> &Session;
 
     // FIXME: These methods should not take an Into<MultiSpan> -- instead, callers should need to
     // set the span in their `decorate` function (preferably using set_span).
diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs
index 8458b53..236eeee 100644
--- a/compiler/rustc_lint/src/context/diagnostics.rs
+++ b/compiler/rustc_lint/src/context/diagnostics.rs
@@ -1,58 +1,57 @@
 #![allow(rustc::diagnostic_outside_of_impl)]
 #![allow(rustc::untranslatable_diagnostic)]
 
+use std::borrow::Cow;
+
 use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
-use rustc_errors::{elided_lifetime_in_path_suggestion, Diag};
-use rustc_errors::{Applicability, SuggestionStyle};
+use rustc_errors::Applicability;
+use rustc_errors::{elided_lifetime_in_path_suggestion, DiagArgValue, MultiSpan};
 use rustc_middle::middle::stability;
-use rustc_session::lint::BuiltinLintDiag;
-use rustc_session::Session;
+use rustc_session::lint::{BuiltinLintDiag, Lint};
 use rustc_span::BytePos;
 
+use crate::{lints, EarlyContext, LintContext as _};
+
 mod check_cfg;
 
-pub(super) fn builtin(sess: &Session, diagnostic: BuiltinLintDiag, diag: &mut Diag<'_, ()>) {
+pub(super) fn emit_buffered_lint(
+    ctx: &EarlyContext<'_>,
+    lint: &'static Lint,
+    span: MultiSpan,
+    diagnostic: BuiltinLintDiag,
+) {
+    let sess = ctx.sess();
     match diagnostic {
-        BuiltinLintDiag::UnicodeTextFlow(span, content) => {
+        BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => {
             let spans: Vec<_> = content
                 .char_indices()
                 .filter_map(|(i, c)| {
                     TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
-                        let lo = span.lo() + BytePos(2 + i as u32);
-                        (c, span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
+                        let lo = comment_span.lo() + BytePos(2 + i as u32);
+                        (c, comment_span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
                     })
                 })
                 .collect();
-            let (an, s) = match spans.len() {
-                1 => ("an ", ""),
-                _ => ("", "s"),
-            };
-            diag.span_label(
+            let characters = spans
+                .iter()
+                .map(|&(c, span)| lints::UnicodeCharNoteSub { span, c_debug: format!("{c:?}") })
+                .collect();
+            let suggestions = (!spans.is_empty()).then_some(lints::UnicodeTextFlowSuggestion {
+                spans: spans.iter().map(|(_c, span)| *span).collect(),
+            });
+            ctx.emit_span_lint(
+                lint,
                 span,
-                format!(
-                    "this comment contains {an}invisible unicode text flow control codepoint{s}",
-                ),
-            );
-            for (c, span) in &spans {
-                diag.span_label(*span, format!("{c:?}"));
-            }
-            diag.note(
-                "these kind of unicode codepoints change the way text flows on \
-                         applications that support them, but can cause confusion because they \
-                         change the order of characters on the screen",
-            );
-            if !spans.is_empty() {
-                diag.multipart_suggestion_with_style(
-                    "if their presence wasn't intentional, you can remove them",
-                    spans.into_iter().map(|(_, span)| (span, "".to_string())).collect(),
-                    Applicability::MachineApplicable,
-                    SuggestionStyle::HideCodeAlways,
-                );
-            }
+                lints::UnicodeTextFlow {
+                    comment_span,
+                    characters,
+                    suggestions,
+                    num_codepoints: spans.len(),
+                },
+            )
         }
-        BuiltinLintDiag::Normal => (),
-        BuiltinLintDiag::AbsPathWithModule(span) => {
-            let (sugg, app) = match sess.source_map().span_to_snippet(span) {
+        BuiltinLintDiag::AbsPathWithModule(mod_span) => {
+            let (replacement, applicability) = match sess.source_map().span_to_snippet(mod_span) {
                 Ok(ref s) => {
                     // FIXME(Manishearth) ideally the emitting code
                     // can tell us whether or not this is global
@@ -62,160 +61,207 @@
                 }
                 Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders),
             };
-            diag.span_suggestion(span, "use `crate`", sugg, app);
-        }
-        BuiltinLintDiag::ProcMacroDeriveResolutionFallback(span) => {
-            diag.span_label(
+            ctx.emit_span_lint(
+                lint,
                 span,
-                "names from parent modules are not accessible without an explicit import",
+                lints::AbsPathWithModule {
+                    sugg: lints::AbsPathWithModuleSugg {
+                        span: mod_span,
+                        applicability,
+                        replacement,
+                    },
+                },
             );
         }
-        BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => {
-            diag.span_note(span_def, "the macro is defined here");
-        }
+        BuiltinLintDiag::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident } => ctx
+            .emit_span_lint(
+                lint,
+                span,
+                lints::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident },
+            ),
+        BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => ctx
+            .emit_span_lint(
+                lint,
+                span,
+                lints::MacroExpandedMacroExportsAccessedByAbsolutePaths { definition: span_def },
+            ),
         BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => {
-            diag.subdiagnostic(
-                sess.dcx(),
-                elided_lifetime_in_path_suggestion(
-                    sess.source_map(),
-                    n,
-                    path_span,
-                    incl_angl_brckt,
-                    insertion_span,
-                ),
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::ElidedLifetimesInPaths {
+                    subdiag: elided_lifetime_in_path_suggestion(
+                        sess.source_map(),
+                        n,
+                        path_span,
+                        incl_angl_brckt,
+                        insertion_span,
+                    ),
+                },
             );
         }
-        BuiltinLintDiag::UnknownCrateTypes(span, note, sugg) => {
-            diag.span_suggestion(span, note, sugg, Applicability::MaybeIncorrect);
+        BuiltinLintDiag::UnknownCrateTypes { span, candidate } => {
+            let sugg = candidate.map(|candidate| lints::UnknownCrateTypesSub { span, candidate });
+            ctx.emit_span_lint(lint, span, lints::UnknownCrateTypes { sugg });
         }
-        BuiltinLintDiag::UnusedImports(message, replaces, in_test_module) => {
-            if !replaces.is_empty() {
-                diag.tool_only_multipart_suggestion(
-                    message,
-                    replaces,
-                    Applicability::MachineApplicable,
-                );
-            }
+        BuiltinLintDiag::UnusedImports {
+            remove_whole_use,
+            num_to_remove,
+            remove_spans,
+            test_module_span,
+            span_snippets,
+        } => {
+            let sugg = if remove_whole_use {
+                lints::UnusedImportsSugg::RemoveWholeUse { span: remove_spans[0] }
+            } else {
+                lints::UnusedImportsSugg::RemoveImports { remove_spans, num_to_remove }
+            };
+            let test_module_span =
+                test_module_span.map(|span| sess.source_map().guess_head_span(span));
 
-            if let Some(span) = in_test_module {
-                diag.span_help(
-                    sess.source_map().guess_head_span(span),
-                    "if this is a test module, consider adding a `#[cfg(test)]` to the containing module",
-                );
-            }
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::UnusedImports {
+                    sugg,
+                    test_module_span,
+                    num_snippets: span_snippets.len(),
+                    span_snippets: DiagArgValue::StrListSepByAnd(
+                        span_snippets.into_iter().map(Cow::Owned).collect(),
+                    ),
+                },
+            );
         }
         BuiltinLintDiag::RedundantImport(spans, ident) => {
-            for (span, is_imported) in spans {
-                let introduced = if is_imported { "imported" } else { "defined" };
-                let span_msg = if span.is_dummy() { "by the extern prelude" } else { "here" };
-                diag.span_label(
-                    span,
-                    format!("the item `{ident}` is already {introduced} {span_msg}"),
-                );
-            }
+            let subs = spans
+                .into_iter()
+                .map(|(span, is_imported)| {
+                    (match (span.is_dummy(), is_imported) {
+                        (false, true) => lints::RedundantImportSub::ImportedHere,
+                        (false, false) => lints::RedundantImportSub::DefinedHere,
+                        (true, true) => lints::RedundantImportSub::ImportedPrelude,
+                        (true, false) => lints::RedundantImportSub::DefinedPrelude,
+                    })(span)
+                })
+                .collect();
+            ctx.emit_span_lint(lint, span, lints::RedundantImport { subs, ident });
         }
-        BuiltinLintDiag::DeprecatedMacro(suggestion, span) => {
-            stability::deprecation_suggestion(diag, "macro", suggestion, span)
-        }
-        BuiltinLintDiag::UnusedDocComment(span) => {
-            diag.span_label(span, "rustdoc does not generate documentation for macro invocations");
-            diag.help("to document an item produced by a macro, \
-                                  the macro must produce the documentation as part of its expansion");
-        }
-        BuiltinLintDiag::PatternsInFnsWithoutBody(span, ident) => {
-            diag.span_suggestion(
-                span,
-                "remove `mut` from the parameter",
-                ident,
-                Applicability::MachineApplicable,
-            );
-        }
-        BuiltinLintDiag::MissingAbi(span, default_abi) => {
-            diag.span_label(span, "ABI should be specified here");
-            diag.help(format!("the default ABI is {}", default_abi.name()));
-        }
-        BuiltinLintDiag::LegacyDeriveHelpers(span) => {
-            diag.span_label(span, "the attribute is introduced here");
-        }
-        BuiltinLintDiag::ProcMacroBackCompat(note) => {
-            diag.note(note);
-        }
-        BuiltinLintDiag::OrPatternsBackCompat(span, suggestion) => {
-            diag.span_suggestion(
-                span,
-                "use pat_param to preserve semantics",
+        BuiltinLintDiag::DeprecatedMacro {
+            suggestion,
+            suggestion_span,
+            note,
+            path,
+            since_kind,
+        } => {
+            let sub = suggestion.map(|suggestion| stability::DeprecationSuggestion {
+                span: suggestion_span,
+                kind: "macro".to_owned(),
                 suggestion,
-                Applicability::MachineApplicable,
+            });
+            ctx.emit_span_lint(
+                lint,
+                span,
+                stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind },
             );
         }
-        BuiltinLintDiag::ReservedPrefix(span) => {
-            diag.span_label(span, "unknown prefix");
-            diag.span_suggestion_verbose(
-                span.shrink_to_hi(),
-                "insert whitespace here to avoid this being parsed as a prefix in Rust 2021",
-                " ",
-                Applicability::MachineApplicable,
+        BuiltinLintDiag::UnusedDocComment(attr_span) => {
+            ctx.emit_span_lint(lint, span, lints::UnusedDocComment { span: attr_span });
+        }
+        BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => {
+            let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span };
+
+            ctx.emit_span_lint(
+                lint,
+                span,
+                if is_foreign {
+                    lints::PatternsInFnsWithoutBody::Foreign { sub }
+                } else {
+                    lints::PatternsInFnsWithoutBody::Bodiless { sub }
+                },
+            );
+        }
+        BuiltinLintDiag::MissingAbi(label_span, default_abi) => {
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::MissingAbi { span: label_span, default_abi: default_abi.name() },
+            );
+        }
+        BuiltinLintDiag::LegacyDeriveHelpers(label_span) => {
+            ctx.emit_span_lint(lint, span, lints::LegacyDeriveHelpers { span: label_span });
+        }
+        BuiltinLintDiag::ProcMacroBackCompat { crate_name, fixed_version } => {
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::ProcMacroBackCompat { crate_name, fixed_version },
+            );
+        }
+        BuiltinLintDiag::OrPatternsBackCompat(suggestion_span, suggestion) => {
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::OrPatternsBackCompat { span: suggestion_span, suggestion },
+            );
+        }
+        BuiltinLintDiag::ReservedPrefix(label_span, prefix) => {
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::ReservedPrefix {
+                    label: label_span,
+                    suggestion: label_span.shrink_to_hi(),
+                    prefix,
+                },
             );
         }
         BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name, invoc_span } => {
-            diag.span_note(
-                        invoc_span,
-                        format!("the built-in attribute `{attr_name}` will be ignored, since it's applied to the macro invocation `{macro_name}`")
-                    );
-        }
-        BuiltinLintDiag::TrailingMacro(is_trailing, name) => {
-            if is_trailing {
-                diag.note("macro invocations at the end of a block are treated as expressions");
-                diag.note(format!("to ignore the value produced by the macro, add a semicolon after the invocation of `{name}`"));
-            }
-        }
-        BuiltinLintDiag::BreakWithLabelAndLoop(span) => {
-            diag.multipart_suggestion(
-                "wrap this expression in parentheses",
-                vec![
-                    (span.shrink_to_lo(), "(".to_string()),
-                    (span.shrink_to_hi(), ")".to_string()),
-                ],
-                Applicability::MachineApplicable,
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name },
             );
         }
-        BuiltinLintDiag::NamedAsmLabel(help) => {
-            diag.help(help);
-            diag.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information");
+        BuiltinLintDiag::TrailingMacro(is_trailing, name) => {
+            ctx.emit_span_lint(lint, span, lints::TrailingMacro { is_trailing, name });
+        }
+        BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => {
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::BreakWithLabelAndLoop {
+                    sub: lints::BreakWithLabelAndLoopSub {
+                        left: sugg_span.shrink_to_lo(),
+                        right: sugg_span.shrink_to_hi(),
+                    },
+                },
+            );
         }
         BuiltinLintDiag::UnexpectedCfgName(name, value) => {
-            check_cfg::unexpected_cfg_name(sess, diag, name, value)
+            ctx.emit_span_lint(lint, span, check_cfg::unexpected_cfg_name(sess, name, value));
         }
         BuiltinLintDiag::UnexpectedCfgValue(name, value) => {
-            check_cfg::unexpected_cfg_value(sess, diag, name, value)
+            ctx.emit_span_lint(lint, span, check_cfg::unexpected_cfg_value(sess, name, value));
         }
-        BuiltinLintDiag::DeprecatedWhereclauseLocation(sugg) => {
-            let left_sp = diag.span.primary_span().unwrap();
-            match sugg {
-                Some((right_sp, sugg)) => diag.multipart_suggestion(
-                    "move it to the end of the type declaration",
-                    vec![(left_sp, String::new()), (right_sp, sugg)],
-                    Applicability::MachineApplicable,
-                ),
-                None => diag.span_suggestion(
-                    left_sp,
-                    "remove this `where`",
-                    "",
-                    Applicability::MachineApplicable,
-                ),
+        BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => {
+            let suggestion = match sugg {
+                Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd {
+                    left: left_sp,
+                    right: right_sp,
+                    sugg,
+                },
+                None => lints::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp },
             };
-            diag.note("see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information");
+            ctx.emit_span_lint(lint, span, lints::DeprecatedWhereClauseLocation { suggestion });
         }
         BuiltinLintDiag::SingleUseLifetime {
             param_span,
             use_span: Some((use_span, elide)),
             deletion_span,
+            ident,
         } => {
             debug!(?param_span, ?use_span, ?deletion_span);
-            diag.span_label(param_span, "this lifetime...");
-            diag.span_label(use_span, "...is used only here");
-            if let Some(deletion_span) = deletion_span {
-                let msg = "elide the single-use lifetime";
+            let suggestion = if let Some(deletion_span) = deletion_span {
                 let (use_span, replace_lt) = if elide {
                     let use_span = sess.source_map().span_extend_while_whitespace(use_span);
                     (use_span, String::new())
@@ -226,24 +272,22 @@
 
                 // issue 107998 for the case such as a wrong function pointer type
                 // `deletion_span` is empty and there is no need to report lifetime uses here
-                let suggestions = if deletion_span.is_empty() {
-                    vec![(use_span, replace_lt)]
-                } else {
-                    vec![(deletion_span, String::new()), (use_span, replace_lt)]
-                };
-                diag.multipart_suggestion(msg, suggestions, Applicability::MachineApplicable);
-            }
+                let deletion_span =
+                    if deletion_span.is_empty() { None } else { Some(deletion_span) };
+                Some(lints::SingleUseLifetimeSugg { deletion_span, use_span, replace_lt })
+            } else {
+                None
+            };
+
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::SingleUseLifetime { suggestion, param_span, use_span, ident },
+            );
         }
-        BuiltinLintDiag::SingleUseLifetime { param_span: _, use_span: None, deletion_span } => {
+        BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => {
             debug!(?deletion_span);
-            if let Some(deletion_span) = deletion_span {
-                diag.span_suggestion(
-                    deletion_span,
-                    "elide the unused lifetime",
-                    "",
-                    Applicability::MachineApplicable,
-                );
-            }
+            ctx.emit_span_lint(lint, span, lints::UnusedLifetime { deletion_span, ident });
         }
         BuiltinLintDiag::NamedArgumentUsedPositionally {
             position_sp_to_replace,
@@ -252,19 +296,12 @@
             named_arg_name,
             is_formatting_arg,
         } => {
-            diag.span_label(
-                named_arg_sp,
-                "this named argument is referred to by position in formatting string",
-            );
-            if let Some(positional_arg_for_msg) = position_sp_for_msg {
-                let msg = format!(
-                    "this formatting argument uses named argument `{named_arg_name}` by position"
-                );
-                diag.span_label(positional_arg_for_msg, msg);
-            }
-
-            if let Some(positional_arg_to_replace) = position_sp_to_replace {
-                let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name };
+            let (suggestion, name) = if let Some(positional_arg_to_replace) = position_sp_to_replace
+            {
+                let mut name = named_arg_name.clone();
+                if is_formatting_arg {
+                    name.push('$')
+                };
                 let span_to_replace = if let Ok(positional_arg_content) =
                     sess.source_map().span_to_snippet(positional_arg_to_replace)
                     && positional_arg_content.starts_with(':')
@@ -273,31 +310,40 @@
                 } else {
                     positional_arg_to_replace
                 };
-                diag.span_suggestion_verbose(
-                    span_to_replace,
-                    "use the named argument by name to avoid ambiguity",
+                (Some(span_to_replace), name)
+            } else {
+                (None, String::new())
+            };
+
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::NamedArgumentUsedPositionally {
+                    named_arg_sp,
+                    position_label_sp: position_sp_for_msg,
+                    suggestion,
                     name,
-                    Applicability::MaybeIncorrect,
-                );
-            }
+                    named_arg_name,
+                },
+            )
         }
-        BuiltinLintDiag::ByteSliceInPackedStructWithDerive => {
-            diag.help("consider implementing the trait by hand, or remove the `packed` attribute");
+        BuiltinLintDiag::ByteSliceInPackedStructWithDerive { ty } => {
+            ctx.emit_span_lint(lint, span, lints::ByteSliceInPackedStructWithDerive { ty })
         }
         BuiltinLintDiag::UnusedExternCrate { removal_span } => {
-            diag.span_suggestion(removal_span, "remove it", "", Applicability::MachineApplicable);
+            ctx.emit_span_lint(lint, span, lints::UnusedExternCrate { removal_span })
         }
         BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span } => {
             let suggestion_span = vis_span.between(ident_span);
-            diag.span_suggestion_verbose(
-                suggestion_span,
-                "convert it to a `use`",
-                if vis_span.is_empty() { "use " } else { " use " },
-                Applicability::MachineApplicable,
+            let code = if vis_span.is_empty() { "use " } else { " use " };
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::ExternCrateNotIdiomatic { span: suggestion_span, code },
             );
         }
         BuiltinLintDiag::AmbiguousGlobImports { diag: ambiguity } => {
-            rustc_errors::report_ambiguity_error(diag, ambiguity);
+            ctx.emit_span_lint(lint, span, lints::AmbiguousGlobImports { ambiguity });
         }
         BuiltinLintDiag::AmbiguousGlobReexports {
             name,
@@ -305,15 +351,15 @@
             first_reexport_span,
             duplicate_reexport_span,
         } => {
-            diag.span_label(
-                first_reexport_span,
-                format!("the name `{name}` in the {namespace} namespace is first re-exported here"),
-            );
-            diag.span_label(
-                duplicate_reexport_span,
-                format!(
-                    "but the name `{name}` in the {namespace} namespace is also re-exported here"
-                ),
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::AmbiguousGlobReexports {
+                    first_reexport: first_reexport_span,
+                    duplicate_reexport: duplicate_reexport_span,
+                    name,
+                    namespace,
+                },
             );
         }
         BuiltinLintDiag::HiddenGlobReexports {
@@ -322,30 +368,127 @@
             glob_reexport_span,
             private_item_span,
         } => {
-            diag.span_note(glob_reexport_span, format!("the name `{name}` in the {namespace} namespace is supposed to be publicly re-exported here"));
-            diag.span_note(private_item_span, "but the private item here shadows it".to_owned());
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::HiddenGlobReexports {
+                    glob_reexport: glob_reexport_span,
+                    private_item: private_item_span,
+
+                    name,
+                    namespace,
+                },
+            );
         }
         BuiltinLintDiag::UnusedQualifications { removal_span } => {
-            diag.span_suggestion_verbose(
-                removal_span,
-                "remove the unnecessary path segments",
-                "",
-                Applicability::MachineApplicable,
+            ctx.emit_span_lint(lint, span, lints::UnusedQualifications { removal_span });
+        }
+        BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span: lt_span } => {
+            let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span };
+            let code = if elided { "'static " } else { "'static" };
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::AssociatedConstElidedLifetime { span: lt_span, code, elided },
             );
         }
-        BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span } => {
-            diag.span_suggestion_verbose(
-                if elided { span.shrink_to_hi() } else { span },
-                "use the `'static` lifetime",
-                if elided { "'static " } else { "'static" },
-                Applicability::MachineApplicable,
+        BuiltinLintDiag::RedundantImportVisibility { max_vis, span: vis_span, import_vis } => {
+            ctx.emit_span_lint(
+                lint,
+                span,
+                lints::RedundantImportVisibility { span: vis_span, help: (), max_vis, import_vis },
             );
         }
-        BuiltinLintDiag::RedundantImportVisibility { max_vis, span } => {
-            diag.span_note(span, format!("the most public imported item is `{max_vis}`"));
-            diag.help(
-                "reduce the glob import's visibility or increase visibility of imported items",
-            );
+        BuiltinLintDiag::UnknownDiagnosticAttribute { span: typo_span, typo_name } => {
+            let typo = typo_name.map(|typo_name| lints::UnknownDiagnosticAttributeTypoSugg {
+                span: typo_span,
+                typo_name,
+            });
+            ctx.emit_span_lint(lint, span, lints::UnknownDiagnosticAttribute { typo });
         }
+        BuiltinLintDiag::MacroUseDeprecated => {
+            ctx.emit_span_lint(lint, span, lints::MacroUseDeprecated)
+        }
+        BuiltinLintDiag::UnusedMacroUse => ctx.emit_span_lint(lint, span, lints::UnusedMacroUse),
+        BuiltinLintDiag::PrivateExternCrateReexport(ident) => {
+            ctx.emit_span_lint(lint, span, lints::PrivateExternCrateReexport { ident })
+        }
+        BuiltinLintDiag::UnusedLabel => ctx.emit_span_lint(lint, span, lints::UnusedLabel),
+        BuiltinLintDiag::MacroIsPrivate(ident) => {
+            ctx.emit_span_lint(lint, span, lints::MacroIsPrivate { ident })
+        }
+        BuiltinLintDiag::UnusedMacroDefinition(name) => {
+            ctx.emit_span_lint(lint, span, lints::UnusedMacroDefinition { name })
+        }
+        BuiltinLintDiag::MacroRuleNeverUsed(n, name) => {
+            ctx.emit_span_lint(lint, span, lints::MacroRuleNeverUsed { n: n + 1, name })
+        }
+        BuiltinLintDiag::UnstableFeature(msg) => {
+            ctx.emit_span_lint(lint, span, lints::UnstableFeature { msg })
+        }
+        BuiltinLintDiag::AvoidUsingIntelSyntax => {
+            ctx.emit_span_lint(lint, span, lints::AvoidIntelSyntax)
+        }
+        BuiltinLintDiag::AvoidUsingAttSyntax => {
+            ctx.emit_span_lint(lint, span, lints::AvoidAttSyntax)
+        }
+        BuiltinLintDiag::IncompleteInclude => {
+            ctx.emit_span_lint(lint, span, lints::IncompleteInclude)
+        }
+        BuiltinLintDiag::UnnameableTestItems => {
+            ctx.emit_span_lint(lint, span, lints::UnnameableTestItems)
+        }
+        BuiltinLintDiag::DuplicateMacroAttribute => {
+            ctx.emit_span_lint(lint, span, lints::DuplicateMacroAttribute)
+        }
+        BuiltinLintDiag::CfgAttrNoAttributes => {
+            ctx.emit_span_lint(lint, span, lints::CfgAttrNoAttributes)
+        }
+        BuiltinLintDiag::CrateTypeInCfgAttr => {
+            ctx.emit_span_lint(lint, span, lints::CrateTypeInCfgAttr)
+        }
+        BuiltinLintDiag::CrateNameInCfgAttr => {
+            ctx.emit_span_lint(lint, span, lints::CrateNameInCfgAttr)
+        }
+        BuiltinLintDiag::MissingFragmentSpecifier => {
+            ctx.emit_span_lint(lint, span, lints::MissingFragmentSpecifier)
+        }
+        BuiltinLintDiag::MetaVariableStillRepeating(name) => {
+            ctx.emit_span_lint(lint, span, lints::MetaVariableStillRepeating { name })
+        }
+        BuiltinLintDiag::MetaVariableWrongOperator => {
+            ctx.emit_span_lint(lint, span, lints::MetaVariableWrongOperator)
+        }
+        BuiltinLintDiag::DuplicateMatcherBinding => {
+            ctx.emit_span_lint(lint, span, lints::DuplicateMatcherBinding)
+        }
+        BuiltinLintDiag::UnknownMacroVariable(name) => {
+            ctx.emit_span_lint(lint, span, lints::UnknownMacroVariable { name })
+        }
+        BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => ctx.emit_span_lint(
+            lint,
+            span,
+            lints::UnusedCrateDependency { extern_crate, local_crate },
+        ),
+        BuiltinLintDiag::WasmCAbi => ctx.emit_span_lint(lint, span, lints::WasmCAbi),
+        BuiltinLintDiag::IllFormedAttributeInput { suggestions } => ctx.emit_span_lint(
+            lint,
+            span,
+            lints::IllFormedAttributeInput {
+                num_suggestions: suggestions.len(),
+                suggestions: DiagArgValue::StrListSepByAnd(
+                    suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
+                ),
+            },
+        ),
+        BuiltinLintDiag::InnerAttributeUnstable { is_macro } => ctx.emit_span_lint(
+            lint,
+            span,
+            if is_macro {
+                lints::InnerAttributeUnstable::InnerMacroAttribute
+            } else {
+                lints::InnerAttributeUnstable::CustomInnerAttribute
+            },
+        ),
     }
 }
diff --git a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
index 3c423b4..020ca17 100644
--- a/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
+++ b/compiler/rustc_lint/src/context/diagnostics/check_cfg.rs
@@ -1,52 +1,52 @@
-use rustc_errors::{Applicability, Diag};
 use rustc_middle::bug;
 use rustc_session::{config::ExpectedValues, Session};
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::{sym, Span, Symbol};
 
+use crate::lints;
+
 const MAX_CHECK_CFG_NAMES_OR_VALUES: usize = 35;
 
-fn check_cfg_expected_note(
+fn sort_and_truncate_possibilities(
     sess: &Session,
-    possibilities: &[Symbol],
-    type_: &str,
-    name: Option<Symbol>,
-    suffix: &str,
-) -> String {
-    use std::fmt::Write;
-
+    mut possibilities: Vec<Symbol>,
+) -> (Vec<Symbol>, usize) {
     let n_possibilities = if sess.opts.unstable_opts.check_cfg_all_expected {
         possibilities.len()
     } else {
         std::cmp::min(possibilities.len(), MAX_CHECK_CFG_NAMES_OR_VALUES)
     };
 
-    let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
-    possibilities.sort();
+    possibilities.sort_by(|s1, s2| s1.as_str().cmp(s2.as_str()));
 
     let and_more = possibilities.len().saturating_sub(n_possibilities);
-    let possibilities = possibilities[..n_possibilities].join("`, `");
+    possibilities.truncate(n_possibilities);
+    (possibilities, and_more)
+}
 
-    let mut note = String::with_capacity(50 + possibilities.len());
+enum EscapeQuotes {
+    Yes,
+    No,
+}
 
-    write!(&mut note, "expected {type_}").unwrap();
-    if let Some(name) = name {
-        write!(&mut note, " for `{name}`").unwrap();
+fn to_check_cfg_arg(name: Symbol, value: Option<Symbol>, quotes: EscapeQuotes) -> String {
+    if let Some(value) = value {
+        let value = str::escape_debug(value.as_str()).to_string();
+        let values = match quotes {
+            EscapeQuotes::Yes => format!("\\\"{}\\\"", value.replace("\"", "\\\\\\\\\"")),
+            EscapeQuotes::No => format!("\"{value}\""),
+        };
+        format!("cfg({name}, values({values}))")
+    } else {
+        format!("cfg({name})")
     }
-    write!(&mut note, " are: {suffix}`{possibilities}`").unwrap();
-    if and_more > 0 {
-        write!(&mut note, " and {and_more} more").unwrap();
-    }
-
-    note
 }
 
 pub(super) fn unexpected_cfg_name(
     sess: &Session,
-    diag: &mut Diag<'_, ()>,
     (name, name_span): (Symbol, Span),
     value: Option<(Symbol, Span)>,
-) {
+) -> lints::UnexpectedCfgName {
     #[allow(rustc::potential_query_instability)]
     let possibilities: Vec<Symbol> = sess.psess.check_config.expecteds.keys().copied().collect();
 
@@ -69,116 +69,122 @@
     let is_from_cargo = rustc_session::utils::was_invoked_from_cargo();
     let mut is_feature_cfg = name == sym::feature;
 
-    if is_feature_cfg && is_from_cargo {
-        diag.help("consider defining some features in `Cargo.toml`");
+    let code_sugg = if is_feature_cfg && is_from_cargo {
+        lints::unexpected_cfg_name::CodeSuggestion::DefineFeatures
     // Suggest the most probable if we found one
     } else if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
+        is_feature_cfg |= best_match == sym::feature;
+
         if let Some(ExpectedValues::Some(best_match_values)) =
             sess.psess.check_config.expecteds.get(&best_match)
         {
             // We will soon sort, so the initial order does not matter.
             #[allow(rustc::potential_query_instability)]
-            let mut possibilities =
-                best_match_values.iter().flatten().map(Symbol::as_str).collect::<Vec<_>>();
-            possibilities.sort();
+            let mut possibilities = best_match_values.iter().flatten().collect::<Vec<_>>();
+            possibilities.sort_by_key(|s| s.as_str());
 
-            let mut should_print_possibilities = true;
+            let get_possibilities_sub = || {
+                if !possibilities.is_empty() {
+                    let possibilities =
+                        possibilities.iter().copied().cloned().collect::<Vec<_>>().into();
+                    Some(lints::unexpected_cfg_name::ExpectedValues { best_match, possibilities })
+                } else {
+                    None
+                }
+            };
+
             if let Some((value, value_span)) = value {
                 if best_match_values.contains(&Some(value)) {
-                    diag.span_suggestion(
-                        name_span,
-                        "there is a config with a similar name and value",
-                        best_match,
-                        Applicability::MaybeIncorrect,
-                    );
-                    should_print_possibilities = false;
+                    lints::unexpected_cfg_name::CodeSuggestion::SimilarNameAndValue {
+                        span: name_span,
+                        code: best_match.to_string(),
+                    }
                 } else if best_match_values.contains(&None) {
-                    diag.span_suggestion(
-                        name_span.to(value_span),
-                        "there is a config with a similar name and no value",
-                        best_match,
-                        Applicability::MaybeIncorrect,
-                    );
-                    should_print_possibilities = false;
+                    lints::unexpected_cfg_name::CodeSuggestion::SimilarNameNoValue {
+                        span: name_span.to(value_span),
+                        code: best_match.to_string(),
+                    }
                 } else if let Some(first_value) = possibilities.first() {
-                    diag.span_suggestion(
-                        name_span.to(value_span),
-                        "there is a config with a similar name and different values",
-                        format!("{best_match} = \"{first_value}\""),
-                        Applicability::MaybeIncorrect,
-                    );
+                    lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
+                        span: name_span.to(value_span),
+                        code: format!("{best_match} = \"{first_value}\""),
+                        expected: get_possibilities_sub(),
+                    }
                 } else {
-                    diag.span_suggestion(
-                        name_span.to(value_span),
-                        "there is a config with a similar name and different values",
-                        best_match,
-                        Applicability::MaybeIncorrect,
-                    );
-                };
+                    lints::unexpected_cfg_name::CodeSuggestion::SimilarNameDifferentValues {
+                        span: name_span.to(value_span),
+                        code: best_match.to_string(),
+                        expected: get_possibilities_sub(),
+                    }
+                }
             } else {
-                diag.span_suggestion(
-                    name_span,
-                    "there is a config with a similar name",
-                    best_match,
-                    Applicability::MaybeIncorrect,
-                );
-            }
-
-            if !possibilities.is_empty() && should_print_possibilities {
-                let possibilities = possibilities.join("`, `");
-                diag.help(format!("expected values for `{best_match}` are: `{possibilities}`"));
+                lints::unexpected_cfg_name::CodeSuggestion::SimilarName {
+                    span: name_span,
+                    code: best_match.to_string(),
+                    expected: get_possibilities_sub(),
+                }
             }
         } else {
-            diag.span_suggestion(
-                name_span,
-                "there is a config with a similar name",
-                best_match,
-                Applicability::MaybeIncorrect,
-            );
-        }
-
-        is_feature_cfg |= best_match == sym::feature;
-    } else {
-        if !names_possibilities.is_empty() && names_possibilities.len() <= 3 {
-            names_possibilities.sort();
-            for cfg_name in names_possibilities.iter() {
-                diag.span_suggestion(
-                    name_span,
-                    "found config with similar value",
-                    format!("{cfg_name} = \"{name}\""),
-                    Applicability::MaybeIncorrect,
-                );
+            lints::unexpected_cfg_name::CodeSuggestion::SimilarName {
+                span: name_span,
+                code: best_match.to_string(),
+                expected: None,
             }
         }
-        if !possibilities.is_empty() {
-            diag.help_once(check_cfg_expected_note(sess, &possibilities, "names", None, ""));
-        }
-    }
-
-    let inst = if let Some((value, _value_span)) = value {
-        let pre = if is_from_cargo { "\\" } else { "" };
-        format!("cfg({name}, values({pre}\"{value}{pre}\"))")
     } else {
-        format!("cfg({name})")
+        let similar_values = if !names_possibilities.is_empty() && names_possibilities.len() <= 3 {
+            names_possibilities.sort();
+            names_possibilities
+                .iter()
+                .map(|cfg_name| lints::unexpected_cfg_name::FoundWithSimilarValue {
+                    span: name_span,
+                    code: format!("{cfg_name} = \"{name}\""),
+                })
+                .collect()
+        } else {
+            vec![]
+        };
+        let expected_names = if !possibilities.is_empty() {
+            let (possibilities, and_more) = sort_and_truncate_possibilities(sess, possibilities);
+            Some(lints::unexpected_cfg_name::ExpectedNames {
+                possibilities: possibilities.into(),
+                and_more,
+            })
+        } else {
+            None
+        };
+        lints::unexpected_cfg_name::CodeSuggestion::SimilarValues {
+            with_similar_values: similar_values,
+            expected_names,
+        }
     };
 
-    if is_from_cargo {
-        if !is_feature_cfg {
-            diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo::rustc-check-cfg={inst}\");` to the top of the `build.rs`"));
-        }
-        diag.note("see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration");
+    let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes);
+
+    let invocation_help = if is_from_cargo {
+        let sub = if !is_feature_cfg {
+            Some(lints::UnexpectedCfgCargoHelp::new(
+                &inst(EscapeQuotes::No),
+                &inst(EscapeQuotes::Yes),
+            ))
+        } else {
+            None
+        };
+        lints::unexpected_cfg_name::InvocationHelp::Cargo { sub }
     } else {
-        diag.help(format!("to expect this configuration use `--check-cfg={inst}`"));
-        diag.note("see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration");
-    }
+        lints::unexpected_cfg_name::InvocationHelp::Rustc(lints::UnexpectedCfgRustcHelp::new(
+            &inst(EscapeQuotes::No),
+        ))
+    };
+
+    lints::UnexpectedCfgName { code_sugg, invocation_help, name }
 }
 
 pub(super) fn unexpected_cfg_value(
     sess: &Session,
-    diag: &mut Diag<'_, ()>,
     (name, name_span): (Symbol, Span),
     value: Option<(Symbol, Span)>,
-) {
+) -> lints::UnexpectedCfgValue {
     let Some(ExpectedValues::Some(values)) = &sess.psess.check_config.expecteds.get(&name) else {
         bug!(
             "it shouldn't be possible to have a diagnostic on a value whose name is not in values"
@@ -198,81 +204,90 @@
 
     // Show the full list if all possible values for a given name, but don't do it
     // for names as the possibilities could be very long
-    if !possibilities.is_empty() {
-        diag.note(check_cfg_expected_note(
-            sess,
-            &possibilities,
-            "values",
-            Some(name),
-            if have_none_possibility { "(none), " } else { "" },
-        ));
+    let code_sugg = if !possibilities.is_empty() {
+        let expected_values = {
+            let (possibilities, and_more) =
+                sort_and_truncate_possibilities(sess, possibilities.clone());
+            lints::unexpected_cfg_value::ExpectedValues {
+                name,
+                have_none_possibility,
+                possibilities: possibilities.into(),
+                and_more,
+            }
+        };
 
-        if let Some((value, value_span)) = value {
+        let suggestion = if let Some((value, value_span)) = value {
             // Suggest the most probable if we found one
             if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
-                diag.span_suggestion(
-                    value_span,
-                    "there is a expected value with a similar name",
-                    format!("\"{best_match}\""),
-                    Applicability::MaybeIncorrect,
-                );
+                Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SimilarName {
+                    span: value_span,
+                    best_match,
+                })
+            } else {
+                None
             }
         } else if let &[first_possibility] = &possibilities[..] {
-            diag.span_suggestion(
-                name_span.shrink_to_hi(),
-                "specify a config value",
-                format!(" = \"{first_possibility}\""),
-                Applicability::MaybeIncorrect,
-            );
-        }
-    } else if have_none_possibility {
-        diag.note(format!("no expected value for `{name}`"));
-        if let Some((_value, value_span)) = value {
-            diag.span_suggestion(
-                name_span.shrink_to_hi().to(value_span),
-                "remove the value",
-                "",
-                Applicability::MaybeIncorrect,
-            );
-        }
-    } else {
-        diag.note(format!("no expected values for `{name}`"));
+            Some(lints::unexpected_cfg_value::ChangeValueSuggestion::SpecifyValue {
+                span: name_span.shrink_to_hi(),
+                first_possibility,
+            })
+        } else {
+            None
+        };
 
-        let sp = if let Some((_value, value_span)) = value {
+        lints::unexpected_cfg_value::CodeSuggestion::ChangeValue { expected_values, suggestion }
+    } else if have_none_possibility {
+        let suggestion =
+            value.map(|(_value, value_span)| lints::unexpected_cfg_value::RemoveValueSuggestion {
+                span: name_span.shrink_to_hi().to(value_span),
+            });
+        lints::unexpected_cfg_value::CodeSuggestion::RemoveValue { suggestion, name }
+    } else {
+        let span = if let Some((_value, value_span)) = value {
             name_span.to(value_span)
         } else {
             name_span
         };
-        diag.span_suggestion(sp, "remove the condition", "", Applicability::MaybeIncorrect);
-    }
+        let suggestion = lints::unexpected_cfg_value::RemoveConditionSuggestion { span };
+        lints::unexpected_cfg_value::CodeSuggestion::RemoveCondition { suggestion, name }
+    };
 
     // We don't want to suggest adding values to well known names
     // since those are defined by rustc it-self. Users can still
     // do it if they want, but should not encourage them.
     let is_cfg_a_well_know_name = sess.psess.check_config.well_known_names.contains(&name);
 
-    let inst = if let Some((value, _value_span)) = value {
-        let pre = if is_from_cargo { "\\" } else { "" };
-        format!("cfg({name}, values({pre}\"{value}{pre}\"))")
-    } else {
-        format!("cfg({name})")
-    };
+    let inst = |escape_quotes| to_check_cfg_arg(name, value.map(|(v, _s)| v), escape_quotes);
 
-    if is_from_cargo {
-        if name == sym::feature {
+    let invocation_help = if is_from_cargo {
+        let help = if name == sym::feature {
             if let Some((value, _value_span)) = value {
-                diag.help(format!("consider adding `{value}` as a feature in `Cargo.toml`"));
+                Some(lints::unexpected_cfg_value::CargoHelp::AddFeature { value })
             } else {
-                diag.help("consider defining some features in `Cargo.toml`");
+                Some(lints::unexpected_cfg_value::CargoHelp::DefineFeatures)
             }
         } else if !is_cfg_a_well_know_name {
-            diag.help(format!("consider using a Cargo feature instead or adding `println!(\"cargo::rustc-check-cfg={inst}\");` to the top of the `build.rs`"));
-        }
-        diag.note("see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration");
+            Some(lints::unexpected_cfg_value::CargoHelp::Other(lints::UnexpectedCfgCargoHelp::new(
+                &inst(EscapeQuotes::No),
+                &inst(EscapeQuotes::Yes),
+            )))
+        } else {
+            None
+        };
+        lints::unexpected_cfg_value::InvocationHelp::Cargo(help)
     } else {
-        if !is_cfg_a_well_know_name {
-            diag.help(format!("to expect this configuration use `--check-cfg={inst}`"));
-        }
-        diag.note("see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration");
+        let help = if !is_cfg_a_well_know_name {
+            Some(lints::UnexpectedCfgRustcHelp::new(&inst(EscapeQuotes::No)))
+        } else {
+            None
+        };
+        lints::unexpected_cfg_value::InvocationHelp::Rustc(help)
+    };
+
+    lints::UnexpectedCfgValue {
+        code_sugg,
+        invocation_help,
+        has_value: value.is_some(),
+        value: value.map_or_else(String::new, |(v, _span)| v.to_string()),
     }
 }
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 3f627ba..736c7a1 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -14,7 +14,7 @@
 //! upon. As the ast is traversed, this keeps track of the current lint level
 //! for all lint attributes.
 
-use crate::context::{EarlyContext, LintContext, LintStore};
+use crate::context::{EarlyContext, LintStore};
 use crate::passes::{EarlyLintPass, EarlyLintPassObject};
 use rustc_ast::ptr::P;
 use rustc_ast::visit::{self as ast_visit, walk_list, Visitor};
@@ -44,14 +44,8 @@
     #[allow(rustc::diagnostic_outside_of_impl)]
     fn inlined_check_id(&mut self, id: ast::NodeId) {
         for early_lint in self.context.buffered.take(id) {
-            let BufferedEarlyLint { span, msg, node_id: _, lint_id, diagnostic } = early_lint;
-            self.context.span_lint_with_diagnostics(
-                lint_id.lint,
-                Some(span),
-                msg,
-                |_| {},
-                diagnostic,
-            );
+            let BufferedEarlyLint { span, node_id: _, lint_id, diagnostic } = early_lint;
+            self.context.span_lint_with_diagnostics(lint_id.lint, span, diagnostic);
         }
     }
 
diff --git a/compiler/rustc_lint/src/for_loops_over_fallibles.rs b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
index ce3f45a..a6876d8 100644
--- a/compiler/rustc_lint/src/for_loops_over_fallibles.rs
+++ b/compiler/rustc_lint/src/for_loops_over_fallibles.rs
@@ -9,7 +9,7 @@
 use hir::{Expr, Pat};
 use rustc_hir as hir;
 use rustc_infer::{infer::TyCtxtInferExt, traits::ObligationCause};
-use rustc_middle::ty::{self, List};
+use rustc_middle::ty;
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::{sym, Span};
 use rustc_trait_selection::traits::ObligationCtxt;
@@ -123,7 +123,7 @@
 fn suggest_question_mark<'tcx>(
     cx: &LateContext<'tcx>,
     adt: ty::AdtDef<'tcx>,
-    args: &List<ty::GenericArg<'tcx>>,
+    args: ty::GenericArgsRef<'tcx>,
     span: Span,
 ) -> bool {
     let Some(body_id) = cx.enclosing_body else { return false };
@@ -150,11 +150,8 @@
     let ocx = ObligationCtxt::new(&infcx);
 
     let body_def_id = cx.tcx.hir().body_owner_def_id(body_id);
-    let cause = ObligationCause::new(
-        span,
-        body_def_id,
-        rustc_infer::traits::ObligationCauseCode::MiscObligation,
-    );
+    let cause =
+        ObligationCause::new(span, body_def_id, rustc_infer::traits::ObligationCauseCode::Misc);
 
     ocx.register_bound(
         cause,
diff --git a/compiler/rustc_lint/src/foreign_modules.rs b/compiler/rustc_lint/src/foreign_modules.rs
index 48e5683..2c86964 100644
--- a/compiler/rustc_lint/src/foreign_modules.rs
+++ b/compiler/rustc_lint/src/foreign_modules.rs
@@ -345,8 +345,8 @@
                     let a_sig = tcx.instantiate_bound_regions_with_erased(a_poly_sig);
                     let b_sig = tcx.instantiate_bound_regions_with_erased(b_poly_sig);
 
-                    (a_sig.abi, a_sig.unsafety, a_sig.c_variadic)
-                        == (b_sig.abi, b_sig.unsafety, b_sig.c_variadic)
+                    (a_sig.abi, a_sig.safety, a_sig.c_variadic)
+                        == (b_sig.abi, b_sig.safety, b_sig.c_variadic)
                         && a_sig.inputs().iter().eq_by(b_sig.inputs().iter(), |a, b| {
                             structurally_same_type_impl(seen_types, tcx, param_env, *a, *b, ckind)
                         })
diff --git a/compiler/rustc_lint/src/impl_trait_overcaptures.rs b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
new file mode 100644
index 0000000..30bf80b
--- /dev/null
+++ b/compiler/rustc_lint/src/impl_trait_overcaptures.rs
@@ -0,0 +1,425 @@
+use rustc_data_structures::fx::FxIndexSet;
+use rustc_data_structures::unord::UnordSet;
+use rustc_errors::{Applicability, LintDiagnostic};
+use rustc_hir as hir;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_macros::LintDiagnostic;
+use rustc_middle::middle::resolve_bound_vars::ResolvedArg;
+use rustc_middle::ty::{
+    self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
+};
+use rustc_middle::{bug, span_bug};
+use rustc_session::{declare_lint, declare_lint_pass};
+use rustc_span::{sym, BytePos, Span};
+
+use crate::fluent_generated as fluent;
+use crate::{LateContext, LateLintPass};
+
+declare_lint! {
+    /// The `impl_trait_overcaptures` lint warns against cases where lifetime
+    /// capture behavior will differ in edition 2024.
+    ///
+    /// In the 2024 edition, `impl Trait`s will capture all lifetimes in scope,
+    /// rather than just the lifetimes that are mentioned in the bounds of the type.
+    /// Often these sets are equal, but if not, it means that the `impl Trait` may
+    /// cause erroneous borrow-checker errors.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// # #![feature(precise_capturing)]
+    /// # #![allow(incomplete_features)]
+    /// # #![deny(impl_trait_overcaptures)]
+    /// # use std::fmt::Display;
+    /// let mut x = vec![];
+    /// x.push(1);
+    ///
+    /// fn test(x: &Vec<i32>) -> impl Display {
+    ///     x[0]
+    /// }
+    ///
+    /// let element = test(&x);
+    /// x.push(2);
+    /// println!("{element}");
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// In edition < 2024, the returned `impl Display` doesn't capture the
+    /// lifetime from the `&Vec<i32>`, so the vector can be mutably borrowed
+    /// while the `impl Display` is live.
+    ///
+    /// To fix this, we can explicitly state that the `impl Display` doesn't
+    /// capture any lifetimes, using `impl use<> Display`.
+    pub IMPL_TRAIT_OVERCAPTURES,
+    Allow,
+    "`impl Trait` will capture more lifetimes than possibly intended in edition 2024",
+    @feature_gate = sym::precise_capturing;
+    //@future_incompatible = FutureIncompatibleInfo {
+    //    reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
+    //    reference: "<FIXME>",
+    //};
+}
+
+declare_lint! {
+    /// The `impl_trait_redundant_captures` lint warns against cases where use of the
+    /// precise capturing `use<...>` syntax is not needed.
+    ///
+    /// In the 2024 edition, `impl Trait`s will capture all lifetimes in scope.
+    /// If precise-capturing `use<...>` syntax is used, and the set of parameters
+    /// that are captures are *equal* to the set of parameters in scope, then
+    /// the syntax is redundant, and can be removed.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,compile_fail
+    /// # #![feature(precise_capturing, lifetime_capture_rules_2024)]
+    /// # #![allow(incomplete_features)]
+    /// # #![deny(impl_trait_redundant_captures)]
+    /// fn test<'a>(x: &'a i32) -> impl use<'a> Sized { x }
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// To fix this, remove the `use<'a>`, since the lifetime is already captured
+    /// since it is in scope.
+    pub IMPL_TRAIT_REDUNDANT_CAPTURES,
+    Warn,
+    "redundant precise-capturing `use<...>` syntax on an `impl Trait`",
+    @feature_gate = sym::precise_capturing;
+}
+
+declare_lint_pass!(
+    /// Lint for opaque types that will begin capturing in-scope but unmentioned lifetimes
+    /// in edition 2024.
+    ImplTraitOvercaptures => [IMPL_TRAIT_OVERCAPTURES, IMPL_TRAIT_REDUNDANT_CAPTURES]
+);
+
+impl<'tcx> LateLintPass<'tcx> for ImplTraitOvercaptures {
+    fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::Item<'tcx>) {
+        match &it.kind {
+            hir::ItemKind::Fn(..) => check_fn(cx.tcx, it.owner_id.def_id),
+            _ => {}
+        }
+    }
+
+    fn check_impl_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::ImplItem<'tcx>) {
+        match &it.kind {
+            hir::ImplItemKind::Fn(_, _) => check_fn(cx.tcx, it.owner_id.def_id),
+            _ => {}
+        }
+    }
+
+    fn check_trait_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx hir::TraitItem<'tcx>) {
+        match &it.kind {
+            hir::TraitItemKind::Fn(_, _) => check_fn(cx.tcx, it.owner_id.def_id),
+            _ => {}
+        }
+    }
+}
+
+fn check_fn(tcx: TyCtxt<'_>, parent_def_id: LocalDefId) {
+    let sig = tcx.fn_sig(parent_def_id).instantiate_identity();
+
+    let mut in_scope_parameters = FxIndexSet::default();
+    // Populate the in_scope_parameters list first with all of the generics in scope
+    let mut current_def_id = Some(parent_def_id.to_def_id());
+    while let Some(def_id) = current_def_id {
+        let generics = tcx.generics_of(def_id);
+        for param in &generics.own_params {
+            in_scope_parameters.insert(param.def_id);
+        }
+        current_def_id = generics.parent;
+    }
+
+    // Then visit the signature to walk through all the binders (incl. the late-bound
+    // vars on the function itself, which we need to count too).
+    sig.visit_with(&mut VisitOpaqueTypes {
+        tcx,
+        parent_def_id,
+        in_scope_parameters,
+        seen: Default::default(),
+    });
+}
+
+struct VisitOpaqueTypes<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    parent_def_id: LocalDefId,
+    in_scope_parameters: FxIndexSet<DefId>,
+    seen: FxIndexSet<LocalDefId>,
+}
+
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for VisitOpaqueTypes<'tcx> {
+    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
+        &mut self,
+        t: &ty::Binder<'tcx, T>,
+    ) -> Self::Result {
+        // When we get into a binder, we need to add its own bound vars to the scope.
+        let mut added = vec![];
+        for arg in t.bound_vars() {
+            let arg: ty::BoundVariableKind = arg;
+            match arg {
+                ty::BoundVariableKind::Region(ty::BoundRegionKind::BrNamed(def_id, ..))
+                | ty::BoundVariableKind::Ty(ty::BoundTyKind::Param(def_id, _)) => {
+                    added.push(def_id);
+                    let unique = self.in_scope_parameters.insert(def_id);
+                    assert!(unique);
+                }
+                _ => {
+                    self.tcx.dcx().span_delayed_bug(
+                        self.tcx.def_span(self.parent_def_id),
+                        format!("unsupported bound variable kind: {arg:?}"),
+                    );
+                }
+            }
+        }
+
+        t.super_visit_with(self);
+
+        // And remove them. The `shift_remove` should be `O(1)` since we're popping
+        // them off from the end.
+        for arg in added.into_iter().rev() {
+            self.in_scope_parameters.shift_remove(&arg);
+        }
+    }
+
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
+        if !t.has_aliases() {
+            return;
+        }
+
+        if let ty::Alias(ty::Projection, opaque_ty) = *t.kind()
+            && self.tcx.is_impl_trait_in_trait(opaque_ty.def_id)
+        {
+            // visit the opaque of the RPITIT
+            self.tcx
+                .type_of(opaque_ty.def_id)
+                .instantiate(self.tcx, opaque_ty.args)
+                .visit_with(self)
+        } else if let ty::Alias(ty::Opaque, opaque_ty) = *t.kind()
+            && let Some(opaque_def_id) = opaque_ty.def_id.as_local()
+            // Don't recurse infinitely on an opaque
+            && self.seen.insert(opaque_def_id)
+            // If it's owned by this function
+            && let opaque =
+                self.tcx.hir_node_by_def_id(opaque_def_id).expect_item().expect_opaque_ty()
+            && let hir::OpaqueTyOrigin::FnReturn(parent_def_id) = opaque.origin
+            && parent_def_id == self.parent_def_id
+        {
+            // Compute the set of args that are captured by the opaque...
+            let mut captured = FxIndexSet::default();
+            let variances = self.tcx.variances_of(opaque_def_id);
+            let mut current_def_id = Some(opaque_def_id.to_def_id());
+            while let Some(def_id) = current_def_id {
+                let generics = self.tcx.generics_of(def_id);
+                for param in &generics.own_params {
+                    // A param is captured if it's invariant.
+                    if variances[param.index as usize] != ty::Invariant {
+                        continue;
+                    }
+                    // We need to turn all `ty::Param`/`ConstKind::Param` and
+                    // `ReEarlyParam`/`ReBound` into def ids.
+                    captured.insert(extract_def_id_from_arg(
+                        self.tcx,
+                        generics,
+                        opaque_ty.args[param.index as usize],
+                    ));
+                }
+                current_def_id = generics.parent;
+            }
+
+            // Compute the set of in scope params that are not captured. Get their spans,
+            // since that's all we really care about them for emitting the diagnostic.
+            let uncaptured_spans: Vec<_> = self
+                .in_scope_parameters
+                .iter()
+                .filter(|def_id| !captured.contains(*def_id))
+                .map(|def_id| self.tcx.def_span(def_id))
+                .collect();
+
+            let opaque_span = self.tcx.def_span(opaque_def_id);
+            let new_capture_rules =
+                opaque_span.at_least_rust_2024() || self.tcx.features().lifetime_capture_rules_2024;
+
+            // If we have uncaptured args, and if the opaque doesn't already have
+            // `use<>` syntax on it, and we're < edition 2024, then warn the user.
+            if !new_capture_rules
+                && opaque.precise_capturing_args.is_none()
+                && !uncaptured_spans.is_empty()
+            {
+                let suggestion = if let Ok(snippet) =
+                    self.tcx.sess.source_map().span_to_snippet(opaque_span)
+                    && snippet.starts_with("impl ")
+                {
+                    let (lifetimes, others): (Vec<_>, Vec<_>) = captured
+                        .into_iter()
+                        .partition(|def_id| self.tcx.def_kind(*def_id) == DefKind::LifetimeParam);
+                    // Take all lifetime params first, then all others (ty/ct).
+                    let generics: Vec<_> = lifetimes
+                        .into_iter()
+                        .chain(others)
+                        .map(|def_id| self.tcx.item_name(def_id).to_string())
+                        .collect();
+                    // Make sure that we're not trying to name any APITs
+                    if generics.iter().all(|name| !name.starts_with("impl ")) {
+                        Some((
+                            format!(" use<{}>", generics.join(", ")),
+                            opaque_span.with_lo(opaque_span.lo() + BytePos(4)).shrink_to_lo(),
+                        ))
+                    } else {
+                        None
+                    }
+                } else {
+                    None
+                };
+
+                self.tcx.emit_node_span_lint(
+                    IMPL_TRAIT_OVERCAPTURES,
+                    self.tcx.local_def_id_to_hir_id(opaque_def_id),
+                    opaque_span,
+                    ImplTraitOvercapturesLint {
+                        self_ty: t,
+                        num_captured: uncaptured_spans.len(),
+                        uncaptured_spans,
+                        suggestion,
+                    },
+                );
+            }
+            // Otherwise, if we are edition 2024, have `use<>` syntax, and
+            // have no uncaptured args, then we should warn to the user that
+            // it's redundant to capture all args explicitly.
+            else if new_capture_rules
+                && let Some((captured_args, capturing_span)) = opaque.precise_capturing_args
+            {
+                let mut explicitly_captured = UnordSet::default();
+                for arg in captured_args {
+                    match self.tcx.named_bound_var(arg.hir_id()) {
+                        Some(
+                            ResolvedArg::EarlyBound(def_id) | ResolvedArg::LateBound(_, _, def_id),
+                        ) => {
+                            if self.tcx.def_kind(self.tcx.parent(def_id)) == DefKind::OpaqueTy {
+                                let (ty::ReEarlyParam(ty::EarlyParamRegion { def_id, .. })
+                                | ty::ReLateParam(ty::LateParamRegion {
+                                    bound_region: ty::BoundRegionKind::BrNamed(def_id, _),
+                                    ..
+                                })) = self
+                                    .tcx
+                                    .map_opaque_lifetime_to_parent_lifetime(def_id.expect_local())
+                                    .kind()
+                                else {
+                                    span_bug!(
+                                        self.tcx.def_span(def_id),
+                                        "variable should have been duplicated from a parent"
+                                    );
+                                };
+                                explicitly_captured.insert(def_id);
+                            } else {
+                                explicitly_captured.insert(def_id);
+                            }
+                        }
+                        _ => {
+                            self.tcx.dcx().span_delayed_bug(
+                                self.tcx.hir().span(arg.hir_id()),
+                                "no valid for captured arg",
+                            );
+                        }
+                    }
+                }
+
+                if self
+                    .in_scope_parameters
+                    .iter()
+                    .all(|def_id| explicitly_captured.contains(def_id))
+                {
+                    self.tcx.emit_node_span_lint(
+                        IMPL_TRAIT_REDUNDANT_CAPTURES,
+                        self.tcx.local_def_id_to_hir_id(opaque_def_id),
+                        opaque_span,
+                        ImplTraitRedundantCapturesLint { capturing_span },
+                    );
+                }
+            }
+
+            // Walk into the bounds of the opaque, too, since we want to get nested opaques
+            // in this lint as well. Interestingly, one place that I expect this lint to fire
+            // is for `impl for<'a> Bound<Out = impl Other>`, since `impl Other` will begin
+            // to capture `'a` in e2024 (even though late-bound vars in opaques are not allowed).
+            for clause in
+                self.tcx.item_bounds(opaque_ty.def_id).iter_instantiated(self.tcx, opaque_ty.args)
+            {
+                clause.visit_with(self)
+            }
+        }
+
+        t.super_visit_with(self);
+    }
+}
+
+struct ImplTraitOvercapturesLint<'tcx> {
+    uncaptured_spans: Vec<Span>,
+    self_ty: Ty<'tcx>,
+    num_captured: usize,
+    suggestion: Option<(String, Span)>,
+}
+
+impl<'a> LintDiagnostic<'a, ()> for ImplTraitOvercapturesLint<'_> {
+    fn decorate_lint<'b>(self, diag: &'b mut rustc_errors::Diag<'a, ()>) {
+        diag.arg("self_ty", self.self_ty.to_string())
+            .arg("num_captured", self.num_captured)
+            .span_note(self.uncaptured_spans, fluent::lint_note)
+            .note(fluent::lint_note2);
+        if let Some((suggestion, span)) = self.suggestion {
+            diag.span_suggestion(
+                span,
+                fluent::lint_suggestion,
+                suggestion,
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
+    fn msg(&self) -> rustc_errors::DiagMessage {
+        fluent::lint_impl_trait_overcaptures
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_impl_trait_redundant_captures)]
+struct ImplTraitRedundantCapturesLint {
+    #[suggestion(lint_suggestion, code = "", applicability = "machine-applicable")]
+    capturing_span: Span,
+}
+
+fn extract_def_id_from_arg<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    generics: &'tcx ty::Generics,
+    arg: ty::GenericArg<'tcx>,
+) -> DefId {
+    match arg.unpack() {
+        ty::GenericArgKind::Lifetime(re) => match *re {
+            ty::ReEarlyParam(ebr) => generics.region_param(ebr, tcx).def_id,
+            ty::ReBound(
+                _,
+                ty::BoundRegion { kind: ty::BoundRegionKind::BrNamed(def_id, ..), .. },
+            ) => def_id,
+            _ => unreachable!(),
+        },
+        ty::GenericArgKind::Type(ty) => {
+            let ty::Param(param_ty) = *ty.kind() else {
+                bug!();
+            };
+            generics.type_param(param_ty, tcx).def_id
+        }
+        ty::GenericArgKind::Const(ct) => {
+            let ty::ConstKind::Param(param_ct) = ct.kind() else {
+                bug!();
+            };
+            generics.const_param(param_ct, tcx).def_id
+        }
+    }
+}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index a78b410..64fcc7e 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -42,7 +42,6 @@
 #[macro_use]
 extern crate tracing;
 
-mod array_into_iter;
 mod async_fn_in_trait;
 pub mod builtin;
 mod context;
@@ -55,6 +54,7 @@
 mod for_loops_over_fallibles;
 mod foreign_modules;
 pub mod hidden_unicode_codepoints;
+mod impl_trait_overcaptures;
 mod internal;
 mod invalid_from_utf8;
 mod late;
@@ -75,18 +75,18 @@
 mod ptr_nulls;
 mod redundant_semicolon;
 mod reference_casting;
+mod shadowed_into_iter;
 mod traits;
 mod types;
 mod unit_bindings;
 mod unused;
 
-pub use array_into_iter::ARRAY_INTO_ITER;
+pub use shadowed_into_iter::{ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER};
 
 use rustc_hir::def_id::LocalModDefId;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::TyCtxt;
 
-use array_into_iter::ArrayIntoIter;
 use async_fn_in_trait::AsyncFnInTrait;
 use builtin::*;
 use deref_into_dyn_supertrait::*;
@@ -94,6 +94,7 @@
 use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
 use for_loops_over_fallibles::*;
 use hidden_unicode_codepoints::*;
+use impl_trait_overcaptures::ImplTraitOvercaptures;
 use internal::*;
 use invalid_from_utf8::*;
 use let_underscore::*;
@@ -110,6 +111,7 @@
 use ptr_nulls::*;
 use redundant_semicolon::*;
 use reference_casting::*;
+use shadowed_into_iter::ShadowedIntoIter;
 use traits::*;
 use types::*;
 use unit_bindings::*;
@@ -213,7 +215,7 @@
             DerefNullPtr: DerefNullPtr,
             UnstableFeatures: UnstableFeatures,
             UngatedAsyncFnTrackCaller: UngatedAsyncFnTrackCaller,
-            ArrayIntoIter: ArrayIntoIter::default(),
+            ShadowedIntoIter: ShadowedIntoIter,
             DropTraitConstraints: DropTraitConstraints,
             TemporaryCStringAsPtr: TemporaryCStringAsPtr,
             NonPanicFmt: NonPanicFmt,
@@ -228,6 +230,7 @@
             MissingDoc: MissingDoc,
             AsyncFnInTrait: AsyncFnInTrait,
             NonLocalDefinitions: NonLocalDefinitions::default(),
+            ImplTraitOvercaptures: ImplTraitOvercaptures,
         ]
     ]
 );
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 7efa524..3bd6fac 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -5,16 +5,22 @@
 use crate::errors::RequestedLevel;
 use crate::fluent_generated as fluent;
 use rustc_errors::{
-    codes::*, Applicability, Diag, DiagMessage, DiagStyledString, EmissionGuarantee,
-    LintDiagnostic, SubdiagMessageOp, Subdiagnostic, SuggestionStyle,
+    codes::*, Applicability, Diag, DiagArgValue, DiagMessage, DiagStyledString,
+    ElidedLifetimeInPathSubdiag, EmissionGuarantee, LintDiagnostic, SubdiagMessageOp,
+    Subdiagnostic, SuggestionStyle,
 };
-use rustc_hir::def_id::DefId;
+use rustc_hir::{def::Namespace, def_id::DefId};
 use rustc_macros::{LintDiagnostic, Subdiagnostic};
 use rustc_middle::ty::{
     inhabitedness::InhabitedPredicate, Clause, PolyExistentialTraitRef, Ty, TyCtxt,
 };
-use rustc_session::Session;
-use rustc_span::{edition::Edition, sym, symbol::Ident, Span, Symbol};
+use rustc_session::{lint::AmbiguityErrorDiag, Session};
+use rustc_span::{
+    edition::Edition,
+    sym,
+    symbol::{Ident, MacroRulesNormalizedIdent},
+    Span, Symbol,
+};
 
 use crate::{
     builtin::InitError, builtin::TypeAliasBounds, errors::OverruledAttributeSub, LateContext,
@@ -22,17 +28,18 @@
 
 // array_into_iter.rs
 #[derive(LintDiagnostic)]
-#[diag(lint_array_into_iter)]
-pub struct ArrayIntoIterDiag<'a> {
-    pub target: &'a str,
+#[diag(lint_shadowed_into_iter)]
+pub struct ShadowedIntoIterDiag {
+    pub target: &'static str,
+    pub edition: &'static str,
     #[suggestion(lint_use_iter_suggestion, code = "iter", applicability = "machine-applicable")]
     pub suggestion: Span,
     #[subdiagnostic]
-    pub sub: Option<ArrayIntoIterDiagSub>,
+    pub sub: Option<ShadowedIntoIterDiagSub>,
 }
 
 #[derive(Subdiagnostic)]
-pub enum ArrayIntoIterDiagSub {
+pub enum ShadowedIntoIterDiagSub {
     #[suggestion(lint_remove_into_iter_suggestion, code = "", applicability = "maybe-incorrect")]
     RemoveIntoIter {
         #[primary_span]
@@ -1946,3 +1953,837 @@
     #[label]
     pub label: Span,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(lint_builtin_asm_labels)]
+#[help]
+#[note]
+pub struct BuiltinNamedAsmLabel;
+
+#[derive(Subdiagnostic)]
+#[help(lint_unexpected_cfg_add_cargo_feature)]
+#[help(lint_unexpected_cfg_add_cargo_toml_lint_cfg)]
+#[help(lint_unexpected_cfg_add_build_rs_println)]
+pub struct UnexpectedCfgCargoHelp {
+    pub build_rs_println: String,
+    pub cargo_toml_lint_cfg: String,
+}
+
+impl UnexpectedCfgCargoHelp {
+    pub fn new(unescaped: &str, escaped: &str) -> Self {
+        Self {
+            cargo_toml_lint_cfg: format!(
+                "\n [lints.rust]\n unexpected_cfgs = {{ level = \"warn\", check-cfg = ['{unescaped}'] }}",
+            ),
+            build_rs_println: format!("println!(\"cargo::rustc-check-cfg={escaped}\");",),
+        }
+    }
+}
+
+#[derive(Subdiagnostic)]
+#[help(lint_unexpected_cfg_add_cmdline_arg)]
+pub struct UnexpectedCfgRustcHelp {
+    pub cmdline_arg: String,
+}
+
+impl UnexpectedCfgRustcHelp {
+    pub fn new(unescaped: &str) -> Self {
+        Self { cmdline_arg: format!("--check-cfg={unescaped}") }
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unexpected_cfg_name)]
+pub struct UnexpectedCfgName {
+    #[subdiagnostic]
+    pub code_sugg: unexpected_cfg_name::CodeSuggestion,
+    #[subdiagnostic]
+    pub invocation_help: unexpected_cfg_name::InvocationHelp,
+
+    pub name: Symbol,
+}
+
+pub mod unexpected_cfg_name {
+    use rustc_errors::DiagSymbolList;
+    use rustc_macros::Subdiagnostic;
+    use rustc_span::{Span, Symbol};
+
+    #[derive(Subdiagnostic)]
+    pub enum CodeSuggestion {
+        #[help(lint_unexpected_cfg_define_features)]
+        DefineFeatures,
+        #[suggestion(
+            lint_unexpected_cfg_name_similar_name_value,
+            applicability = "maybe-incorrect",
+            code = "{code}"
+        )]
+        SimilarNameAndValue {
+            #[primary_span]
+            span: Span,
+            code: String,
+        },
+        #[suggestion(
+            lint_unexpected_cfg_name_similar_name_no_value,
+            applicability = "maybe-incorrect",
+            code = "{code}"
+        )]
+        SimilarNameNoValue {
+            #[primary_span]
+            span: Span,
+            code: String,
+        },
+        #[suggestion(
+            lint_unexpected_cfg_name_similar_name_different_values,
+            applicability = "maybe-incorrect",
+            code = "{code}"
+        )]
+        SimilarNameDifferentValues {
+            #[primary_span]
+            span: Span,
+            code: String,
+            #[subdiagnostic]
+            expected: Option<ExpectedValues>,
+        },
+        #[suggestion(
+            lint_unexpected_cfg_name_similar_name,
+            applicability = "maybe-incorrect",
+            code = "{code}"
+        )]
+        SimilarName {
+            #[primary_span]
+            span: Span,
+            code: String,
+            #[subdiagnostic]
+            expected: Option<ExpectedValues>,
+        },
+        SimilarValues {
+            #[subdiagnostic]
+            with_similar_values: Vec<FoundWithSimilarValue>,
+            #[subdiagnostic]
+            expected_names: Option<ExpectedNames>,
+        },
+    }
+
+    #[derive(Subdiagnostic)]
+    #[help(lint_unexpected_cfg_name_expected_values)]
+    pub struct ExpectedValues {
+        pub best_match: Symbol,
+        pub possibilities: DiagSymbolList,
+    }
+
+    #[derive(Subdiagnostic)]
+    #[suggestion(
+        lint_unexpected_cfg_name_with_similar_value,
+        applicability = "maybe-incorrect",
+        code = "{code}"
+    )]
+    pub struct FoundWithSimilarValue {
+        #[primary_span]
+        pub span: Span,
+        pub code: String,
+    }
+
+    #[derive(Subdiagnostic)]
+    #[help_once(lint_unexpected_cfg_name_expected_names)]
+    pub struct ExpectedNames {
+        pub possibilities: DiagSymbolList,
+        pub and_more: usize,
+    }
+
+    #[derive(Subdiagnostic)]
+    pub enum InvocationHelp {
+        #[note(lint_unexpected_cfg_doc_cargo)]
+        Cargo {
+            #[subdiagnostic]
+            sub: Option<super::UnexpectedCfgCargoHelp>,
+        },
+        #[note(lint_unexpected_cfg_doc_rustc)]
+        Rustc(#[subdiagnostic] super::UnexpectedCfgRustcHelp),
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unexpected_cfg_value)]
+pub struct UnexpectedCfgValue {
+    #[subdiagnostic]
+    pub code_sugg: unexpected_cfg_value::CodeSuggestion,
+    #[subdiagnostic]
+    pub invocation_help: unexpected_cfg_value::InvocationHelp,
+
+    pub has_value: bool,
+    pub value: String,
+}
+
+pub mod unexpected_cfg_value {
+    use rustc_errors::DiagSymbolList;
+    use rustc_macros::Subdiagnostic;
+    use rustc_span::{Span, Symbol};
+
+    #[derive(Subdiagnostic)]
+    pub enum CodeSuggestion {
+        ChangeValue {
+            #[subdiagnostic]
+            expected_values: ExpectedValues,
+            #[subdiagnostic]
+            suggestion: Option<ChangeValueSuggestion>,
+        },
+        #[note(lint_unexpected_cfg_value_no_expected_value)]
+        RemoveValue {
+            #[subdiagnostic]
+            suggestion: Option<RemoveValueSuggestion>,
+
+            name: Symbol,
+        },
+        #[note(lint_unexpected_cfg_value_no_expected_values)]
+        RemoveCondition {
+            #[subdiagnostic]
+            suggestion: RemoveConditionSuggestion,
+
+            name: Symbol,
+        },
+    }
+
+    #[derive(Subdiagnostic)]
+    pub enum ChangeValueSuggestion {
+        #[suggestion(
+            lint_unexpected_cfg_value_similar_name,
+            code = r#""{best_match}""#,
+            applicability = "maybe-incorrect"
+        )]
+        SimilarName {
+            #[primary_span]
+            span: Span,
+            best_match: Symbol,
+        },
+        #[suggestion(
+            lint_unexpected_cfg_value_specify_value,
+            code = r#" = "{first_possibility}""#,
+            applicability = "maybe-incorrect"
+        )]
+        SpecifyValue {
+            #[primary_span]
+            span: Span,
+            first_possibility: Symbol,
+        },
+    }
+
+    #[derive(Subdiagnostic)]
+    #[suggestion(
+        lint_unexpected_cfg_value_remove_value,
+        code = "",
+        applicability = "maybe-incorrect"
+    )]
+    pub struct RemoveValueSuggestion {
+        #[primary_span]
+        pub span: Span,
+    }
+
+    #[derive(Subdiagnostic)]
+    #[suggestion(
+        lint_unexpected_cfg_value_remove_condition,
+        code = "",
+        applicability = "maybe-incorrect"
+    )]
+    pub struct RemoveConditionSuggestion {
+        #[primary_span]
+        pub span: Span,
+    }
+
+    #[derive(Subdiagnostic)]
+    #[note(lint_unexpected_cfg_value_expected_values)]
+    pub struct ExpectedValues {
+        pub name: Symbol,
+        pub have_none_possibility: bool,
+        pub possibilities: DiagSymbolList,
+        pub and_more: usize,
+    }
+
+    #[derive(Subdiagnostic)]
+    pub enum InvocationHelp {
+        #[note(lint_unexpected_cfg_doc_cargo)]
+        Cargo(#[subdiagnostic] Option<CargoHelp>),
+        #[note(lint_unexpected_cfg_doc_rustc)]
+        Rustc(#[subdiagnostic] Option<super::UnexpectedCfgRustcHelp>),
+    }
+
+    #[derive(Subdiagnostic)]
+    pub enum CargoHelp {
+        #[help(lint_unexpected_cfg_value_add_feature)]
+        AddFeature {
+            value: Symbol,
+        },
+        #[help(lint_unexpected_cfg_define_features)]
+        DefineFeatures,
+        Other(#[subdiagnostic] super::UnexpectedCfgCargoHelp),
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_macro_use_deprecated)]
+pub struct MacroUseDeprecated;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_macro_use)]
+pub struct UnusedMacroUse;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_private_extern_crate_reexport)]
+pub struct PrivateExternCrateReexport {
+    pub ident: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_label)]
+pub struct UnusedLabel;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_macro_is_private)]
+pub struct MacroIsPrivate {
+    pub ident: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_macro_definition)]
+pub struct UnusedMacroDefinition {
+    pub name: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_macro_rule_never_used)]
+pub struct MacroRuleNeverUsed {
+    pub n: usize,
+    pub name: Symbol,
+}
+
+pub struct UnstableFeature {
+    pub msg: DiagMessage,
+}
+
+impl<'a> LintDiagnostic<'a, ()> for UnstableFeature {
+    fn decorate_lint<'b>(self, _diag: &'b mut Diag<'a, ()>) {}
+
+    fn msg(&self) -> DiagMessage {
+        self.msg.clone()
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_avoid_intel_syntax)]
+pub struct AvoidIntelSyntax;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_avoid_att_syntax)]
+pub struct AvoidAttSyntax;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_incomplete_include)]
+pub struct IncompleteInclude;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unnameable_test_items)]
+pub struct UnnameableTestItems;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_duplicate_macro_attribute)]
+pub struct DuplicateMacroAttribute;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_cfg_attr_no_attributes)]
+pub struct CfgAttrNoAttributes;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_crate_type_in_cfg_attr_deprecated)]
+pub struct CrateTypeInCfgAttr;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_crate_name_in_cfg_attr_deprecated)]
+pub struct CrateNameInCfgAttr;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_missing_fragment_specifier)]
+pub struct MissingFragmentSpecifier;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_metavariable_still_repeating)]
+pub struct MetaVariableStillRepeating {
+    pub name: MacroRulesNormalizedIdent,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_metavariable_wrong_operator)]
+pub struct MetaVariableWrongOperator;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_duplicate_matcher_binding)]
+pub struct DuplicateMatcherBinding;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unknown_macro_variable)]
+pub struct UnknownMacroVariable {
+    pub name: MacroRulesNormalizedIdent,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_crate_dependency)]
+pub struct UnusedCrateDependency {
+    pub extern_crate: Symbol,
+    pub local_crate: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_wasm_c_abi)]
+pub struct WasmCAbi;
+
+#[derive(LintDiagnostic)]
+#[diag(lint_ill_formed_attribute_input)]
+pub struct IllFormedAttributeInput {
+    pub num_suggestions: usize,
+    pub suggestions: DiagArgValue,
+}
+
+#[derive(LintDiagnostic)]
+pub enum InnerAttributeUnstable {
+    #[diag(lint_inner_macro_attribute_unstable)]
+    InnerMacroAttribute,
+    #[diag(lint_custom_inner_attribute_unstable)]
+    CustomInnerAttribute,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unknown_diagnostic_attribute)]
+pub struct UnknownDiagnosticAttribute {
+    #[subdiagnostic]
+    pub typo: Option<UnknownDiagnosticAttributeTypoSugg>,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+    lint_unknown_diagnostic_attribute_typo_sugg,
+    style = "verbose",
+    code = "{typo_name}",
+    applicability = "machine-applicable"
+)]
+pub struct UnknownDiagnosticAttributeTypoSugg {
+    #[primary_span]
+    pub span: Span,
+    pub typo_name: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unicode_text_flow)]
+#[note]
+pub struct UnicodeTextFlow {
+    #[label]
+    pub comment_span: Span,
+    #[subdiagnostic]
+    pub characters: Vec<UnicodeCharNoteSub>,
+    #[subdiagnostic]
+    pub suggestions: Option<UnicodeTextFlowSuggestion>,
+
+    pub num_codepoints: usize,
+}
+
+#[derive(Subdiagnostic)]
+#[label(lint_label_comment_char)]
+pub struct UnicodeCharNoteSub {
+    #[primary_span]
+    pub span: Span,
+    pub c_debug: String,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable", style = "hidden")]
+pub struct UnicodeTextFlowSuggestion {
+    #[suggestion_part(code = "")]
+    pub spans: Vec<Span>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_abs_path_with_module)]
+pub struct AbsPathWithModule {
+    #[subdiagnostic]
+    pub sugg: AbsPathWithModuleSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(lint_suggestion, code = "{replacement}")]
+pub struct AbsPathWithModuleSugg {
+    #[primary_span]
+    pub span: Span,
+    #[applicability]
+    pub applicability: Applicability,
+    pub replacement: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_proc_macro_derive_resolution_fallback)]
+pub struct ProcMacroDeriveResolutionFallback {
+    #[label]
+    pub span: Span,
+    pub ns: Namespace,
+    pub ident: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_macro_expanded_macro_exports_accessed_by_absolute_paths)]
+pub struct MacroExpandedMacroExportsAccessedByAbsolutePaths {
+    #[note]
+    pub definition: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_hidden_lifetime_parameters)]
+pub struct ElidedLifetimesInPaths {
+    #[subdiagnostic]
+    pub subdiag: ElidedLifetimeInPathSubdiag,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_invalid_crate_type_value)]
+pub struct UnknownCrateTypes {
+    #[subdiagnostic]
+    pub sugg: Option<UnknownCrateTypesSub>,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(lint_suggestion, code = r#""{candidate}""#, applicability = "maybe-incorrect")]
+pub struct UnknownCrateTypesSub {
+    #[primary_span]
+    pub span: Span,
+    pub candidate: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_imports)]
+pub struct UnusedImports {
+    #[subdiagnostic]
+    pub sugg: UnusedImportsSugg,
+    #[help]
+    pub test_module_span: Option<Span>,
+
+    pub span_snippets: DiagArgValue,
+    pub num_snippets: usize,
+}
+
+#[derive(Subdiagnostic)]
+pub enum UnusedImportsSugg {
+    #[suggestion(
+        lint_suggestion_remove_whole_use,
+        applicability = "machine-applicable",
+        code = "",
+        style = "tool-only"
+    )]
+    RemoveWholeUse {
+        #[primary_span]
+        span: Span,
+    },
+    #[multipart_suggestion(
+        lint_suggestion_remove_imports,
+        applicability = "machine-applicable",
+        style = "tool-only"
+    )]
+    RemoveImports {
+        #[suggestion_part(code = "")]
+        remove_spans: Vec<Span>,
+        num_to_remove: usize,
+    },
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_redundant_import)]
+pub struct RedundantImport {
+    #[subdiagnostic]
+    pub subs: Vec<RedundantImportSub>,
+
+    pub ident: Ident,
+}
+
+#[derive(Subdiagnostic)]
+pub enum RedundantImportSub {
+    #[label(lint_label_imported_here)]
+    ImportedHere(#[primary_span] Span),
+    #[label(lint_label_defined_here)]
+    DefinedHere(#[primary_span] Span),
+    #[label(lint_label_imported_prelude)]
+    ImportedPrelude(#[primary_span] Span),
+    #[label(lint_label_defined_prelude)]
+    DefinedPrelude(#[primary_span] Span),
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_doc_comment)]
+#[help]
+pub struct UnusedDocComment {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+pub enum PatternsInFnsWithoutBody {
+    #[diag(lint_pattern_in_foreign)]
+    Foreign {
+        #[subdiagnostic]
+        sub: PatternsInFnsWithoutBodySub,
+    },
+    #[diag(lint_pattern_in_bodiless)]
+    Bodiless {
+        #[subdiagnostic]
+        sub: PatternsInFnsWithoutBodySub,
+    },
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(lint_remove_mut_from_pattern, code = "{ident}", applicability = "machine-applicable")]
+pub struct PatternsInFnsWithoutBodySub {
+    #[primary_span]
+    pub span: Span,
+
+    pub ident: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_extern_without_abi)]
+#[help]
+pub struct MissingAbi {
+    #[label]
+    pub span: Span,
+
+    pub default_abi: &'static str,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_legacy_derive_helpers)]
+pub struct LegacyDeriveHelpers {
+    #[label]
+    pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_proc_macro_back_compat)]
+#[note]
+pub struct ProcMacroBackCompat {
+    pub crate_name: String,
+    pub fixed_version: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_or_patterns_back_compat)]
+pub struct OrPatternsBackCompat {
+    #[suggestion(code = "{suggestion}", applicability = "machine-applicable")]
+    pub span: Span,
+    pub suggestion: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_reserved_prefix)]
+pub struct ReservedPrefix {
+    #[label]
+    pub label: Span,
+    #[suggestion(code = " ", applicability = "machine-applicable")]
+    pub suggestion: Span,
+
+    pub prefix: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_builtin_attribute)]
+pub struct UnusedBuiltinAttribute {
+    #[note]
+    pub invoc_span: Span,
+
+    pub attr_name: Symbol,
+    pub macro_name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_trailing_semi_macro)]
+pub struct TrailingMacro {
+    #[note(lint_note1)]
+    #[note(lint_note2)]
+    pub is_trailing: bool,
+
+    pub name: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_break_with_label_and_loop)]
+pub struct BreakWithLabelAndLoop {
+    #[subdiagnostic]
+    pub sub: BreakWithLabelAndLoopSub,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")]
+pub struct BreakWithLabelAndLoopSub {
+    #[suggestion_part(code = "(")]
+    pub left: Span,
+    #[suggestion_part(code = ")")]
+    pub right: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_deprecated_where_clause_location)]
+#[note]
+pub struct DeprecatedWhereClauseLocation {
+    #[subdiagnostic]
+    pub suggestion: DeprecatedWhereClauseLocationSugg,
+}
+
+#[derive(Subdiagnostic)]
+pub enum DeprecatedWhereClauseLocationSugg {
+    #[multipart_suggestion(lint_suggestion_move_to_end, applicability = "machine-applicable")]
+    MoveToEnd {
+        #[suggestion_part(code = "")]
+        left: Span,
+        #[suggestion_part(code = "{sugg}")]
+        right: Span,
+
+        sugg: String,
+    },
+    #[suggestion(lint_suggestion_remove_where, code = "", applicability = "machine-applicable")]
+    RemoveWhere {
+        #[primary_span]
+        span: Span,
+    },
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_single_use_lifetime)]
+pub struct SingleUseLifetime {
+    #[label(lint_label_param)]
+    pub param_span: Span,
+    #[label(lint_label_use)]
+    pub use_span: Span,
+    #[subdiagnostic]
+    pub suggestion: Option<SingleUseLifetimeSugg>,
+
+    pub ident: Ident,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(lint_suggestion, applicability = "machine-applicable")]
+pub struct SingleUseLifetimeSugg {
+    #[suggestion_part(code = "")]
+    pub deletion_span: Option<Span>,
+    #[suggestion_part(code = "{replace_lt}")]
+    pub use_span: Span,
+
+    pub replace_lt: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_lifetime)]
+pub struct UnusedLifetime {
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub deletion_span: Option<Span>,
+
+    pub ident: Ident,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_named_argument_used_positionally)]
+pub struct NamedArgumentUsedPositionally {
+    #[label(lint_label_named_arg)]
+    pub named_arg_sp: Span,
+    #[label(lint_label_position_arg)]
+    pub position_label_sp: Option<Span>,
+    #[suggestion(style = "verbose", code = "{name}", applicability = "maybe-incorrect")]
+    pub suggestion: Option<Span>,
+
+    pub name: String,
+    pub named_arg_name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_byte_slice_in_packed_struct_with_derive)]
+#[help]
+pub struct ByteSliceInPackedStructWithDerive {
+    // FIXME: make this translatable
+    pub ty: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unused_extern_crate)]
+pub struct UnusedExternCrate {
+    #[suggestion(code = "", applicability = "machine-applicable")]
+    pub removal_span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_extern_crate_not_idiomatic)]
+pub struct ExternCrateNotIdiomatic {
+    #[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")]
+    pub span: Span,
+
+    pub code: &'static str,
+}
+
+// FIXME: make this translatable
+pub struct AmbiguousGlobImports {
+    pub ambiguity: AmbiguityErrorDiag,
+}
+
+impl<'a, G: EmissionGuarantee> LintDiagnostic<'a, G> for AmbiguousGlobImports {
+    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) {
+        rustc_errors::report_ambiguity_error(diag, self.ambiguity);
+    }
+
+    fn msg(&self) -> DiagMessage {
+        DiagMessage::Str(self.ambiguity.msg.clone().into())
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_ambiguous_glob_reexport)]
+pub struct AmbiguousGlobReexports {
+    #[label(lint_label_first_reexport)]
+    pub first_reexport: Span,
+    #[label(lint_label_duplicate_reexport)]
+    pub duplicate_reexport: Span,
+
+    pub name: String,
+    // FIXME: make this translatable
+    pub namespace: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_hidden_glob_reexport)]
+pub struct HiddenGlobReexports {
+    #[note(lint_note_glob_reexport)]
+    pub glob_reexport: Span,
+    #[note(lint_note_private_item)]
+    pub private_item: Span,
+
+    pub name: String,
+    // FIXME: make this translatable
+    pub namespace: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_unnecessary_qualification)]
+pub struct UnusedQualifications {
+    #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")]
+    pub removal_span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_associated_const_elided_lifetime)]
+pub struct AssociatedConstElidedLifetime {
+    #[suggestion(style = "verbose", code = "{code}", applicability = "machine-applicable")]
+    pub span: Span,
+
+    pub code: &'static str,
+    pub elided: bool,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_redundant_import_visibility)]
+pub struct RedundantImportVisibility {
+    #[note]
+    pub span: Span,
+    #[help]
+    pub help: (),
+
+    pub import_vis: String,
+    pub max_vis: String,
+}
diff --git a/compiler/rustc_lint/src/non_local_def.rs b/compiler/rustc_lint/src/non_local_def.rs
index 7bdf5ef..b3e9374 100644
--- a/compiler/rustc_lint/src/non_local_def.rs
+++ b/compiler/rustc_lint/src/non_local_def.rs
@@ -1,6 +1,5 @@
 use rustc_hir::{def::DefKind, Body, Item, ItemKind, Node, TyKind};
 use rustc_hir::{Path, QPath};
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::{Obligation, ObligationCause};
 use rustc_middle::ty::{self, Binder, Ty, TyCtxt, TypeFoldable, TypeFolder};
@@ -39,7 +38,7 @@
     ///
     /// Creating non-local definitions go against expectation and can create discrepancies
     /// in tooling. It should be avoided. It may become deny-by-default in edition 2024
-    /// and higher, see see the tracking issue <https://github.com/rust-lang/rust/issues/120363>.
+    /// and higher, see the tracking issue <https://github.com/rust-lang/rust/issues/120363>.
     ///
     /// An `impl` definition is non-local if it is nested inside an item and neither
     /// the type nor the trait are at the same nesting level as the `impl` block.
@@ -337,7 +336,7 @@
         if let Some(def) = t.ty_adt_def()
             && (self.did_has_local_parent)(def.did())
         {
-            self.infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span: self.infer_span })
+            self.infcx.next_ty_var(self.infer_span)
         } else {
             t.super_fold_with(self)
         }
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index 1ea1f49..eda40e4 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -1,9 +1,8 @@
 use rustc_hir as hir;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_macros::{LintDiagnostic, Subdiagnostic};
-use rustc_middle::ty::{
-    self, fold::BottomUpFolder, print::TraitPredPrintModifiersAndPath, Ty, TypeFoldable,
-};
+use rustc_middle::ty::print::{PrintTraitPredicateExt as _, TraitPredPrintModifiersAndPath};
+use rustc_middle::ty::{self, fold::BottomUpFolder, Ty, TypeFoldable};
 use rustc_session::{declare_lint, declare_lint_pass};
 use rustc_span::{symbol::kw, Span};
 use rustc_trait_selection::traits;
@@ -108,8 +107,11 @@
                     return;
                 }
 
-                let proj_ty =
-                    Ty::new_projection(cx.tcx, proj.projection_ty.def_id, proj.projection_ty.args);
+                let proj_ty = Ty::new_projection(
+                    cx.tcx,
+                    proj.projection_term.def_id,
+                    proj.projection_term.args,
+                );
                 // For every instance of the projection type in the bounds,
                 // replace them with the term we're assigning to the associated
                 // type in our opaque type.
@@ -124,8 +126,8 @@
                 // with `impl Send: OtherTrait`.
                 for (assoc_pred, assoc_pred_span) in cx
                     .tcx
-                    .explicit_item_bounds(proj.projection_ty.def_id)
-                    .iter_instantiated_copied(cx.tcx, proj.projection_ty.args)
+                    .explicit_item_bounds(proj.projection_term.def_id)
+                    .iter_instantiated_copied(cx.tcx, proj.projection_term.args)
                 {
                     let assoc_pred = assoc_pred.fold_with(proj_replacer);
                     let Ok(assoc_pred) = traits::fully_normalize(
diff --git a/compiler/rustc_lint/src/reference_casting.rs b/compiler/rustc_lint/src/reference_casting.rs
index 9fed91f..34153e3 100644
--- a/compiler/rustc_lint/src/reference_casting.rs
+++ b/compiler/rustc_lint/src/reference_casting.rs
@@ -199,6 +199,16 @@
     let e_alloc = cx.expr_or_init(e);
     let e_alloc =
         if let ExprKind::AddrOf(_, _, inner_expr) = e_alloc.kind { inner_expr } else { e_alloc };
+
+    // if the current expr looks like this `&mut expr[index]` then just looking
+    // at `expr[index]` won't give us the underlying allocation, so we just skip it
+    // the same logic applies field access `&mut expr.field` and reborrows `&mut *expr`.
+    if let ExprKind::Index(..) | ExprKind::Field(..) | ExprKind::Unary(UnOp::Deref, ..) =
+        e_alloc.kind
+    {
+        return None;
+    }
+
     let alloc_ty = cx.typeck_results().node_type(e_alloc.hir_id);
 
     // if we do not find it we bail out, as this may not be UB
diff --git a/compiler/rustc_lint/src/shadowed_into_iter.rs b/compiler/rustc_lint/src/shadowed_into_iter.rs
new file mode 100644
index 0000000..41ec84f
--- /dev/null
+++ b/compiler/rustc_lint/src/shadowed_into_iter.rs
@@ -0,0 +1,157 @@
+use crate::lints::{ShadowedIntoIterDiag, ShadowedIntoIterDiagSub};
+use crate::{LateContext, LateLintPass, LintContext};
+use rustc_hir as hir;
+use rustc_middle::ty::{self, Ty};
+use rustc_session::lint::FutureIncompatibilityReason;
+use rustc_session::{declare_lint, impl_lint_pass};
+use rustc_span::edition::Edition;
+
+declare_lint! {
+    /// The `array_into_iter` lint detects calling `into_iter` on arrays.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2018
+    /// # #![allow(unused)]
+    /// [1, 2, 3].into_iter().for_each(|n| { *n; });
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Since Rust 1.53, arrays implement `IntoIterator`. However, to avoid
+    /// breakage, `array.into_iter()` in Rust 2015 and 2018 code will still
+    /// behave as `(&array).into_iter()`, returning an iterator over
+    /// references, just like in Rust 1.52 and earlier.
+    /// This only applies to the method call syntax `array.into_iter()`, not to
+    /// any other syntax such as `for _ in array` or `IntoIterator::into_iter(array)`.
+    pub ARRAY_INTO_ITER,
+    Warn,
+    "detects calling `into_iter` on arrays in Rust 2015 and 2018",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2021),
+        reference: "<https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>",
+    };
+}
+
+declare_lint! {
+    /// The `boxed_slice_into_iter` lint detects calling `into_iter` on boxed slices.
+    ///
+    /// ### Example
+    ///
+    /// ```rust,edition2021
+    /// # #![allow(unused)]
+    /// vec![1, 2, 3].into_boxed_slice().into_iter().for_each(|n| { *n; });
+    /// ```
+    ///
+    /// {{produces}}
+    ///
+    /// ### Explanation
+    ///
+    /// Since Rust CURRENT_RUSTC_VERSION, boxed slices implement `IntoIterator`. However, to avoid
+    /// breakage, `boxed_slice.into_iter()` in Rust 2015, 2018, and 2021 code will still
+    /// behave as `(&boxed_slice).into_iter()`, returning an iterator over
+    /// references, just like in Rust CURRENT_RUSTC_VERSION and earlier.
+    /// This only applies to the method call syntax `boxed_slice.into_iter()`, not to
+    /// any other syntax such as `for _ in boxed_slice` or `IntoIterator::into_iter(boxed_slice)`.
+    pub BOXED_SLICE_INTO_ITER,
+    Warn,
+    "detects calling `into_iter` on boxed slices in Rust 2015, 2018, and 2021",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
+    };
+}
+
+#[derive(Copy, Clone)]
+pub struct ShadowedIntoIter;
+
+impl_lint_pass!(ShadowedIntoIter => [ARRAY_INTO_ITER, BOXED_SLICE_INTO_ITER]);
+
+impl<'tcx> LateLintPass<'tcx> for ShadowedIntoIter {
+    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
+        let hir::ExprKind::MethodCall(call, receiver_arg, ..) = &expr.kind else {
+            return;
+        };
+
+        // Check if the method call actually calls the libcore
+        // `IntoIterator::into_iter`.
+        let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) else {
+            return;
+        };
+        if Some(method_def_id) != cx.tcx.lang_items().into_iter_fn() {
+            return;
+        }
+
+        // As this is a method call expression, we have at least one argument.
+        let receiver_ty = cx.typeck_results().expr_ty(receiver_arg);
+        let adjustments = cx.typeck_results().expr_adjustments(receiver_arg);
+
+        let adjusted_receiver_tys: Vec<_> =
+            [receiver_ty].into_iter().chain(adjustments.iter().map(|adj| adj.target)).collect();
+
+        fn is_ref_to_array(ty: Ty<'_>) -> bool {
+            if let ty::Ref(_, pointee_ty, _) = *ty.kind() { pointee_ty.is_array() } else { false }
+        }
+        fn is_boxed_slice(ty: Ty<'_>) -> bool {
+            ty.is_box() && ty.boxed_ty().is_slice()
+        }
+        fn is_ref_to_boxed_slice(ty: Ty<'_>) -> bool {
+            if let ty::Ref(_, pointee_ty, _) = *ty.kind() {
+                is_boxed_slice(pointee_ty)
+            } else {
+                false
+            }
+        }
+
+        let (lint, target, edition, can_suggest_ufcs) =
+            if is_ref_to_array(*adjusted_receiver_tys.last().unwrap())
+                && let Some(idx) = adjusted_receiver_tys
+                    .iter()
+                    .copied()
+                    .take_while(|ty| !is_ref_to_array(*ty))
+                    .position(|ty| ty.is_array())
+            {
+                (ARRAY_INTO_ITER, "[T; N]", "2021", idx == 0)
+            } else if is_ref_to_boxed_slice(*adjusted_receiver_tys.last().unwrap())
+                && let Some(idx) = adjusted_receiver_tys
+                    .iter()
+                    .copied()
+                    .take_while(|ty| !is_ref_to_boxed_slice(*ty))
+                    .position(|ty| is_boxed_slice(ty))
+            {
+                (BOXED_SLICE_INTO_ITER, "Box<[T]>", "2024", idx == 0)
+            } else {
+                return;
+            };
+
+        // If this expression comes from the `IntoIter::into_iter` inside of a for loop,
+        // we should just suggest removing the `.into_iter()` or changing it to `.iter()`
+        // to disambiguate if we want to iterate by-value or by-ref.
+        let sub = if let Some((_, hir::Node::Expr(parent_expr))) =
+            cx.tcx.hir().parent_iter(expr.hir_id).nth(1)
+            && let hir::ExprKind::Match(arg, [_], hir::MatchSource::ForLoopDesugar) =
+                &parent_expr.kind
+            && let hir::ExprKind::Call(path, [_]) = &arg.kind
+            && let hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::IntoIterIntoIter, ..)) =
+                &path.kind
+        {
+            Some(ShadowedIntoIterDiagSub::RemoveIntoIter {
+                span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
+            })
+        } else if can_suggest_ufcs {
+            Some(ShadowedIntoIterDiagSub::UseExplicitIntoIter {
+                start_span: expr.span.shrink_to_lo(),
+                end_span: receiver_arg.span.shrink_to_hi().to(expr.span.shrink_to_hi()),
+            })
+        } else {
+            None
+        };
+
+        cx.emit_span_lint(
+            lint,
+            call.ident.span,
+            ShadowedIntoIterDiag { target, edition, suggestion: call.ident.span, sub },
+        );
+    }
+}
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 4d372d6..8866b2b 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -677,6 +677,33 @@
         }
 
         // Check if LHS needs parens to prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`.
+        //
+        // FIXME: https://github.com/rust-lang/rust/issues/119426
+        // The syntax tree in this code is from after macro expansion, so the
+        // current implementation has both false negatives and false positives
+        // related to expressions containing macros.
+        //
+        //     macro_rules! m1 {
+        //         () => {
+        //             1
+        //         };
+        //     }
+        //
+        //     fn f1() -> u8 {
+        //         // Lint says parens are not needed, but they are.
+        //         (m1! {} + 1)
+        //     }
+        //
+        //     macro_rules! m2 {
+        //         () => {
+        //             loop { break 1; }
+        //         };
+        //     }
+        //
+        //     fn f2() -> u8 {
+        //         // Lint says parens are needed, but they are not.
+        //         (m2!() + 1)
+        //     }
         {
             let mut innermost = inner;
             loop {
@@ -1501,7 +1528,7 @@
 
 impl UnusedImportBraces {
     fn check_use_tree(&self, cx: &EarlyContext<'_>, use_tree: &ast::UseTree, item: &ast::Item) {
-        if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
+        if let ast::UseTreeKind::Nested { ref items, .. } = use_tree.kind {
             // Recursively check nested UseTrees
             for (tree, _) in items {
                 self.check_use_tree(cx, tree, item);
@@ -1522,7 +1549,7 @@
                     rename.unwrap_or(orig_ident).name
                 }
                 ast::UseTreeKind::Glob => Symbol::intern("*"),
-                ast::UseTreeKind::Nested(_) => return,
+                ast::UseTreeKind::Nested { .. } => return,
             };
 
             cx.emit_span_lint(
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index eea3ca4..82f16b3 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -38,7 +38,6 @@
         DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
         DEPRECATED_IN_FUTURE,
         DEPRECATED_WHERE_CLAUSE_LOCATION,
-        DEREFERENCING_MUT_BINDING,
         DUPLICATE_MACRO_ATTRIBUTES,
         ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
         ELIDED_LIFETIMES_IN_PATHS,
@@ -90,6 +89,7 @@
         RUST_2021_INCOMPATIBLE_OR_PATTERNS,
         RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
         RUST_2021_PRELUDE_COLLISIONS,
+        RUST_2024_INCOMPATIBLE_PAT,
         SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
         SINGLE_USE_LIFETIMES,
         SOFT_UNSTABLE,
@@ -1630,34 +1630,34 @@
 }
 
 declare_lint! {
-    /// The `dereferencing_mut_binding` lint detects a `mut x` pattern that resets the binding mode,
-    /// as this behavior will change in rust 2024.
+    /// The `rust_2024_incompatible_pat` lint
+    /// detects patterns whose meaning will change in the Rust 2024 edition.
     ///
     /// ### Example
     ///
-    /// ```rust
-    /// # #![warn(dereferencing_mut_binding)]
-    /// let x = Some(123u32);
-    /// let _y = match &x {
-    ///     Some(mut x) => {
-    ///         x += 1;
-    ///         x
-    ///     }
-    ///     None => 0,
-    /// };
+    /// ```rust,edition2021
+    /// #![feature(ref_pat_eat_one_layer_2024)]
+    /// #![warn(rust_2024_incompatible_pat)]
+    ///
+    /// if let Some(&a) = &Some(&0u8) {
+    ///     let _: u8 = a;
+    /// }
+    /// if let Some(mut _a) = &mut Some(0u8) {
+    ///     _a = 7u8;
+    /// }
     /// ```
     ///
     /// {{produces}}
     ///
     /// ### Explanation
     ///
-    /// Without the `mut`, `x` would have type `&u32`. Pre-2024, adding `mut` makes `x` have type
-    /// `u32`, which was deemed surprising. After edition 2024, adding `mut` will not change the
-    /// type of `x`. This lint warns users of editions before 2024 to update their code.
-    pub DEREFERENCING_MUT_BINDING,
+    /// In Rust 2024 and above, the `mut` keyword does not reset the pattern binding mode,
+    /// and nor do `&` or `&mut` patterns. The lint will suggest code that
+    /// has the same meaning in all editions.
+    pub RUST_2024_INCOMPATIBLE_PAT,
     Allow,
-    "detects `mut x` bindings that change the type of `x`",
-    @feature_gate = sym::mut_preserve_binding_mode_2024;
+    "detects patterns whose meaning will change in Rust 2024",
+    @feature_gate = sym::ref_pat_eat_one_layer_2024;
     // FIXME uncomment below upon stabilization
     /*@future_incompatible = FutureIncompatibleInfo {
         reason: FutureIncompatibilityReason::EditionSemanticsChange(Edition::Edition2024),
@@ -3339,11 +3339,14 @@
     ///
     /// ### Explanation
     ///
-    /// This lint is only active when `--check-cfg` arguments are being passed
-    /// to the compiler and triggers whenever an unexpected condition name or value is used.
+    /// This lint is only active when [`--check-cfg`][check-cfg] arguments are being
+    /// passed to the compiler and triggers whenever an unexpected condition name or value is
+    /// used.
     ///
-    /// The known condition include names or values passed in `--check-cfg`, and some
-    /// well-knows names and values built into the compiler.
+    /// See the [Checking Conditional Configurations][check-cfg] section for more
+    /// details.
+    ///
+    /// [check-cfg]: https://doc.rust-lang.org/nightly/rustc/check-cfg.html
     pub UNEXPECTED_CFGS,
     Warn,
     "detects unexpected names and values in `#[cfg]` conditions",
@@ -4263,8 +4266,7 @@
     ///
     /// // where absurd is a function with the following signature
     /// // (it's sound, because `!` always marks unreachable code):
-    /// fn absurd<T>(_: !) -> T { ... }
-    // FIXME: use `core::convert::absurd` here instead, once it's merged
+    /// fn absurd<T>(never: !) -> T { ... }
     /// ```
     ///
     /// While it's convenient to be able to use non-diverging code in one of the branches (like
@@ -4321,7 +4323,12 @@
     /// [`()`]: https://doc.rust-lang.org/core/primitive.unit.html
     pub NEVER_TYPE_FALLBACK_FLOWING_INTO_UNSAFE,
     Warn,
-    "never type fallback affecting unsafe function calls"
+    "never type fallback affecting unsafe function calls",
+    @future_incompatible = FutureIncompatibleInfo {
+        reason: FutureIncompatibilityReason::FutureReleaseSemanticsChange,
+        reference: "issue #123748 <https://github.com/rust-lang/rust/issues/123748>",
+    };
+    report_in_external_macro
 }
 
 declare_lint! {
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index ed16518..1941b0b 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -6,10 +6,12 @@
     HashStable, StableCompare, StableHasher, ToStableHashKey,
 };
 use rustc_error_messages::{DiagMessage, MultiSpan};
+use rustc_hir::def::Namespace;
 use rustc_hir::HashStableContext;
 use rustc_hir::HirId;
 use rustc_macros::{Decodable, Encodable, HashStable_Generic};
 use rustc_span::edition::Edition;
+use rustc_span::symbol::MacroRulesNormalizedIdent;
 use rustc_span::{sym, symbol::Ident, Span, Symbol};
 use rustc_target::spec::abi::Abi;
 
@@ -565,19 +567,44 @@
     pub b2_help_msgs: Vec<String>,
 }
 
+#[derive(Debug, Clone)]
+pub enum DeprecatedSinceKind {
+    InEffect,
+    InFuture,
+    InVersion(String),
+}
+
 // This could be a closure, but then implementing derive trait
 // becomes hacky (and it gets allocated).
 #[derive(Debug)]
 pub enum BuiltinLintDiag {
-    Normal,
     AbsPathWithModule(Span),
-    ProcMacroDeriveResolutionFallback(Span),
+    ProcMacroDeriveResolutionFallback {
+        span: Span,
+        ns: Namespace,
+        ident: Ident,
+    },
     MacroExpandedMacroExportsAccessedByAbsolutePaths(Span),
     ElidedLifetimesInPaths(usize, Span, bool, Span),
-    UnknownCrateTypes(Span, String, String),
-    UnusedImports(String, Vec<(Span, String)>, Option<Span>),
+    UnknownCrateTypes {
+        span: Span,
+        candidate: Option<Symbol>,
+    },
+    UnusedImports {
+        remove_whole_use: bool,
+        num_to_remove: usize,
+        remove_spans: Vec<Span>,
+        test_module_span: Option<Span>,
+        span_snippets: Vec<String>,
+    },
     RedundantImport(Vec<(Span, bool)>, Ident),
-    DeprecatedMacro(Option<Symbol>, Span),
+    DeprecatedMacro {
+        suggestion: Option<Symbol>,
+        suggestion_span: Span,
+        note: Option<Symbol>,
+        path: String,
+        since_kind: DeprecatedSinceKind,
+    },
     MissingAbi(Span, Abi),
     UnusedDocComment(Span),
     UnusedBuiltinAttribute {
@@ -585,18 +612,24 @@
         macro_name: String,
         invoc_span: Span,
     },
-    PatternsInFnsWithoutBody(Span, Ident),
+    PatternsInFnsWithoutBody {
+        span: Span,
+        ident: Ident,
+        is_foreign: bool,
+    },
     LegacyDeriveHelpers(Span),
-    ProcMacroBackCompat(String),
+    ProcMacroBackCompat {
+        crate_name: String,
+        fixed_version: String,
+    },
     OrPatternsBackCompat(Span, String),
-    ReservedPrefix(Span),
+    ReservedPrefix(Span, String),
     TrailingMacro(bool, Ident),
     BreakWithLabelAndLoop(Span),
-    NamedAsmLabel(String),
     UnicodeTextFlow(Span, String),
     UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
     UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
-    DeprecatedWhereclauseLocation(Option<(Span, String)>),
+    DeprecatedWhereclauseLocation(Span, Option<(Span, String)>),
     SingleUseLifetime {
         /// Span of the parameter which declares this lifetime.
         param_span: Span,
@@ -606,6 +639,7 @@
         /// Span of the single use, or None if the lifetime is never used.
         /// If true, the lifetime will be fully elided.
         use_span: Option<(Span, bool)>,
+        ident: Ident,
     },
     NamedArgumentUsedPositionally {
         /// Span where the named argument is used by position and will be replaced with the named
@@ -620,7 +654,10 @@
         /// Indicates if the named argument is used as a width/precision for formatting
         is_formatting_arg: bool,
     },
-    ByteSliceInPackedStructWithDerive,
+    ByteSliceInPackedStructWithDerive {
+        // FIXME: enum of byte/string
+        ty: String,
+    },
     UnusedExternCrate {
         removal_span: Span,
     },
@@ -662,6 +699,43 @@
     RedundantImportVisibility {
         span: Span,
         max_vis: String,
+        import_vis: String,
+    },
+    UnknownDiagnosticAttribute {
+        span: Span,
+        typo_name: Option<Symbol>,
+    },
+    MacroUseDeprecated,
+    UnusedMacroUse,
+    PrivateExternCrateReexport(Ident),
+    UnusedLabel,
+    MacroIsPrivate(Ident),
+    UnusedMacroDefinition(Symbol),
+    MacroRuleNeverUsed(usize, Symbol),
+    UnstableFeature(DiagMessage),
+    AvoidUsingIntelSyntax,
+    AvoidUsingAttSyntax,
+    IncompleteInclude,
+    UnnameableTestItems,
+    DuplicateMacroAttribute,
+    CfgAttrNoAttributes,
+    CrateTypeInCfgAttr,
+    CrateNameInCfgAttr,
+    MissingFragmentSpecifier,
+    MetaVariableStillRepeating(MacroRulesNormalizedIdent),
+    MetaVariableWrongOperator,
+    DuplicateMatcherBinding,
+    UnknownMacroVariable(MacroRulesNormalizedIdent),
+    UnusedCrateDependency {
+        extern_crate: Symbol,
+        local_crate: Symbol,
+    },
+    WasmCAbi,
+    IllFormedAttributeInput {
+        suggestions: Vec<String>,
+    },
+    InnerAttributeUnstable {
+        is_macro: bool,
     },
 }
 
@@ -672,9 +746,6 @@
     /// The span of code that we are linting on.
     pub span: MultiSpan,
 
-    /// The lint message.
-    pub msg: DiagMessage,
-
     /// The `NodeId` of the AST node that generated the lint.
     pub node_id: NodeId,
 
@@ -702,12 +773,10 @@
         lint: &'static Lint,
         node_id: NodeId,
         span: MultiSpan,
-        msg: impl Into<DiagMessage>,
         diagnostic: BuiltinLintDiag,
     ) {
         let lint_id = LintId::of(lint);
-        let msg = msg.into();
-        self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, msg, diagnostic });
+        self.add_early_lint(BufferedEarlyLint { lint_id, node_id, span, diagnostic });
     }
 
     pub fn take(&mut self, id: NodeId) -> Vec<BufferedEarlyLint> {
@@ -720,20 +789,9 @@
         lint: &'static Lint,
         id: NodeId,
         sp: impl Into<MultiSpan>,
-        msg: impl Into<DiagMessage>,
-    ) {
-        self.add_lint(lint, id, sp.into(), msg, BuiltinLintDiag::Normal)
-    }
-
-    pub fn buffer_lint_with_diagnostic(
-        &mut self,
-        lint: &'static Lint,
-        id: NodeId,
-        sp: impl Into<MultiSpan>,
-        msg: impl Into<DiagMessage>,
         diagnostic: BuiltinLintDiag,
     ) {
-        self.add_lint(lint, id, sp.into(), msg, diagnostic)
+        self.add_lint(lint, id, sp.into(), diagnostic)
     }
 }
 
diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml
index c206380..83fda7e 100644
--- a/compiler/rustc_llvm/Cargo.toml
+++ b/compiler/rustc_llvm/Cargo.toml
@@ -10,5 +10,5 @@
 
 [build-dependencies]
 # tidy-alphabetical-start
-cc = "1.0.90"
+cc = "1.0.97"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index ae481ef..38d4a5e 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -158,7 +158,9 @@
         let slug = subdiag.slug.unwrap_or_else(|| match subdiag.kind {
             SubdiagnosticKind::Label => parse_quote! { _subdiag::label },
             SubdiagnosticKind::Note => parse_quote! { _subdiag::note },
+            SubdiagnosticKind::NoteOnce => parse_quote! { _subdiag::note_once },
             SubdiagnosticKind::Help => parse_quote! { _subdiag::help },
+            SubdiagnosticKind::HelpOnce => parse_quote! { _subdiag::help_once },
             SubdiagnosticKind::Warn => parse_quote! { _subdiag::warn },
             SubdiagnosticKind::Suggestion { .. } => parse_quote! { _subdiag::suggestion },
             SubdiagnosticKind::MultipartSuggestion { .. } => unreachable!(),
@@ -233,9 +235,11 @@
         };
         let fn_ident = format_ident!("{}", subdiag);
         match subdiag {
-            SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
-                Ok(self.add_subdiagnostic(&fn_ident, slug))
-            }
+            SubdiagnosticKind::Note
+            | SubdiagnosticKind::NoteOnce
+            | SubdiagnosticKind::Help
+            | SubdiagnosticKind::HelpOnce
+            | SubdiagnosticKind::Warn => Ok(self.add_subdiagnostic(&fn_ident, slug)),
             SubdiagnosticKind::Label | SubdiagnosticKind::Suggestion { .. } => {
                 throw_invalid_attr!(attr, |diag| diag
                     .help("`#[label]` and `#[suggestion]` can only be applied to fields"));
@@ -347,7 +351,11 @@
                 report_error_if_not_applied_to_span(attr, &info)?;
                 Ok(self.add_spanned_subdiagnostic(binding, &fn_ident, slug))
             }
-            SubdiagnosticKind::Note | SubdiagnosticKind::Help | SubdiagnosticKind::Warn => {
+            SubdiagnosticKind::Note
+            | SubdiagnosticKind::NoteOnce
+            | SubdiagnosticKind::Help
+            | SubdiagnosticKind::HelpOnce
+            | SubdiagnosticKind::Warn => {
                 let inner = info.ty.inner_type();
                 if type_matches_path(inner, &["rustc_span", "Span"])
                     || type_matches_path(inner, &["rustc_span", "MultiSpan"])
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 4523677..69014f3 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -510,11 +510,11 @@
             .map(|binding| self.generate_field_attr_code(binding, kind_stats))
             .collect();
 
-        if kind_slugs.is_empty() {
+        if kind_slugs.is_empty() && !self.has_subdiagnostic {
             if self.is_enum {
                 // It's okay for a variant to not be a subdiagnostic at all..
                 return Ok(quote! {});
-            } else if !self.has_subdiagnostic {
+            } else {
                 // ..but structs should always be _something_.
                 throw_span_err!(
                     self.variant.ast().ident.span().unwrap(),
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index 4684306..05a5a32 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -575,8 +575,12 @@
     Label,
     /// `#[note(...)]`
     Note,
+    /// `#[note_once(...)]`
+    NoteOnce,
     /// `#[help(...)]`
     Help,
+    /// `#[help_once(...)]`
+    HelpOnce,
     /// `#[warning(...)]`
     Warn,
     /// `#[suggestion{,_short,_hidden,_verbose}]`
@@ -624,7 +628,9 @@
         let mut kind = match name {
             "label" => SubdiagnosticKind::Label,
             "note" => SubdiagnosticKind::Note,
+            "note_once" => SubdiagnosticKind::NoteOnce,
             "help" => SubdiagnosticKind::Help,
+            "help_once" => SubdiagnosticKind::HelpOnce,
             "warning" => SubdiagnosticKind::Warn,
             _ => {
                 // Recover old `#[(multipart_)suggestion_*]` syntaxes
@@ -682,7 +688,9 @@
                 match kind {
                     SubdiagnosticKind::Label
                     | SubdiagnosticKind::Note
+                    | SubdiagnosticKind::NoteOnce
                     | SubdiagnosticKind::Help
+                    | SubdiagnosticKind::HelpOnce
                     | SubdiagnosticKind::Warn
                     | SubdiagnosticKind::MultipartSuggestion { .. } => {
                         return Ok(Some(SubdiagnosticVariant { kind, slug: None, no_span: false }));
@@ -836,7 +844,9 @@
             }
             SubdiagnosticKind::Label
             | SubdiagnosticKind::Note
+            | SubdiagnosticKind::NoteOnce
             | SubdiagnosticKind::Help
+            | SubdiagnosticKind::HelpOnce
             | SubdiagnosticKind::Warn => {}
         }
 
@@ -849,7 +859,9 @@
         match self {
             SubdiagnosticKind::Label => write!(f, "label"),
             SubdiagnosticKind::Note => write!(f, "note"),
+            SubdiagnosticKind::NoteOnce => write!(f, "note_once"),
             SubdiagnosticKind::Help => write!(f, "help"),
+            SubdiagnosticKind::HelpOnce => write!(f, "help_once"),
             SubdiagnosticKind::Warn => write!(f, "warn"),
             SubdiagnosticKind::Suggestion { .. } => write!(f, "suggestions_with_style"),
             SubdiagnosticKind::MultipartSuggestion { .. } => {
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index c7b7ead..de9c916 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -108,7 +108,9 @@
         // struct attributes
         diag,
         help,
+        help_once,
         note,
+        note_once,
         warning,
         // field attributes
         skip_arg,
@@ -125,7 +127,9 @@
         // struct attributes
         diag,
         help,
+        help_once,
         note,
+        note_once,
         warning,
         // field attributes
         skip_arg,
@@ -142,7 +146,9 @@
         // struct/variant attributes
         label,
         help,
+        help_once,
         note,
+        note_once,
         warning,
         subdiagnostic,
         suggestion,
diff --git a/compiler/rustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs
index f7a84ba..d41ceb2 100644
--- a/compiler/rustc_macros/src/lift.rs
+++ b/compiler/rustc_macros/src/lift.rs
@@ -41,7 +41,7 @@
 
     s.add_impl_generic(newtcx);
     s.bound_impl(
-        quote!(::rustc_middle::ty::Lift<'__lifted>),
+        quote!(::rustc_middle::ty::Lift<::rustc_middle::ty::TyCtxt<'__lifted>>),
         quote! {
             type Lifted = #lifted;
 
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index 3d0846a..2f5dfad 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -284,8 +284,6 @@
 metadata_unsupported_abi_i686 =
     ABI not supported by `#[link(kind = "raw-dylib")]` on i686
 
-metadata_wasm_c_abi =
-    older versions of the `wasm-bindgen` crate will be incompatible with future versions of Rust; please update to `wasm-bindgen` v0.2.88
 metadata_wasm_import_form =
     wasm import module must be of the form `wasm_import_module = "string"`
 
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 888c242..be1a73e 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -16,10 +16,11 @@
 use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, LOCAL_CRATE};
 use rustc_hir::definitions::Definitions;
 use rustc_index::IndexVec;
+use rustc_middle::bug;
 use rustc_middle::ty::{TyCtxt, TyCtxtFeed};
 use rustc_session::config::{self, CrateType, ExternLocation};
 use rustc_session::cstore::{CrateDepKind, CrateSource, ExternCrate, ExternCrateSource};
-use rustc_session::lint;
+use rustc_session::lint::{self, BuiltinLintDiag};
 use rustc_session::output::validate_crate_name;
 use rustc_session::search_paths::PathKind;
 use rustc_span::edition::Edition;
@@ -974,15 +975,14 @@
             }
 
             self.sess.psess.buffer_lint(
-                    lint::builtin::UNUSED_CRATE_DEPENDENCIES,
-                    span,
-                    ast::CRATE_NODE_ID,
-                    format!(
-                        "external crate `{}` unused in `{}`: remove the dependency or add `use {} as _;`",
-                        name,
-                        self.tcx.crate_name(LOCAL_CRATE),
-                        name),
-                );
+                lint::builtin::UNUSED_CRATE_DEPENDENCIES,
+                span,
+                ast::CRATE_NODE_ID,
+                BuiltinLintDiag::UnusedCrateDependency {
+                    extern_crate: name_interned,
+                    local_crate: self.tcx.crate_name(LOCAL_CRATE),
+                },
+            );
         }
     }
 
@@ -1019,7 +1019,7 @@
                 lint::builtin::WASM_C_ABI,
                 span,
                 ast::CRATE_NODE_ID,
-                crate::fluent_generated::metadata_wasm_c_abi,
+                BuiltinLintDiag::WasmCAbi,
             );
         }
     }
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index 4d1bd45..99181f9 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -59,6 +59,7 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def_id::CrateNum;
+use rustc_middle::bug;
 use rustc_middle::middle::dependency_format::{Dependencies, DependencyList, Linkage};
 use rustc_middle::ty::TyCtxt;
 use rustc_session::config::CrateType;
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index c8162a1..00bb4c4 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -1,28 +1,26 @@
+// tidy-alphabetical-start
+#![allow(internal_features)]
+#![allow(rustc::potential_query_instability)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
-#![feature(rustdoc_internals)]
-#![allow(internal_features)]
+#![feature(coroutines)]
 #![feature(decl_macro)]
 #![feature(error_iter)]
 #![feature(extract_if)]
-#![feature(coroutines)]
+#![feature(if_let_guard)]
 #![feature(iter_from_coroutine)]
 #![feature(let_chains)]
-#![feature(if_let_guard)]
-#![feature(proc_macro_internals)]
 #![feature(macro_metavar_expr)]
 #![feature(min_specialization)]
-#![feature(trusted_len)]
-#![feature(try_blocks)]
 #![feature(never_type)]
-#![allow(rustc::potential_query_instability)]
+#![feature(proc_macro_internals)]
+#![feature(rustdoc_internals)]
+#![feature(trusted_len)]
+// tidy-alphabetical-end
 
 extern crate proc_macro;
 
 #[macro_use]
-extern crate rustc_middle;
-
-#[macro_use]
 extern crate tracing;
 
 pub use rmeta::provide;
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 2a33088..bb68c6e 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -21,6 +21,7 @@
 use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
 use rustc_middle::ty::codec::TyDecoder;
 use rustc_middle::ty::Visibility;
+use rustc_middle::{bug, implement_ty_decoder};
 use rustc_serialize::opaque::MemDecoder;
 use rustc_serialize::{Decodable, Decoder};
 use rustc_session::cstore::{CrateSource, ExternCrate};
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 531b2e0..c783149 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -11,6 +11,7 @@
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPath, DefPathHash};
 use rustc_middle::arena::ArenaAllocatable;
+use rustc_middle::bug;
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::exported_symbols::ExportedSymbol;
 use rustc_middle::middle::stability::DeprecationEntry;
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index c057f7e..db0dc6d 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -20,6 +20,7 @@
 use rustc_middle::ty::fast_reject::{self, TreatParams};
 use rustc_middle::ty::{AssocItemContainer, SymbolName};
 use rustc_middle::util::common::to_readable_str;
+use rustc_middle::{bug, span_bug};
 use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
 use rustc_session::config::{CrateType, OptLevel};
 use rustc_span::hygiene::HygieneEncodeContext;
@@ -1402,7 +1403,7 @@
                 let inferred_outlives = self.tcx.inferred_outlives_of(def_id);
                 record_defaulted_array!(self.tables.inferred_outlives_of[def_id] <- inferred_outlives);
 
-                for param in &g.params {
+                for param in &g.own_params {
                     if let ty::GenericParamDefKind::Const { has_default: true, .. } = param.kind {
                         let default = self.tcx.const_param_default(param.def_id);
                         record!(self.tables.const_param_default[param.def_id] <- default);
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index c9cb2f5..825034c 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -1,15 +1,13 @@
 use crate::creader::CrateMetadataRef;
-use decoder::Metadata;
+pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
+use decoder::{DecodeContext, Metadata};
 use def_path_hash_map::DefPathHashMapRef;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
-use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
-use rustc_middle::middle::lib_features::FeatureStability;
-use table::TableBuilder;
-
+use encoder::EncodeContext;
+pub use encoder::{encode_metadata, rendered_const, EncodedMetadata};
 use rustc_ast as ast;
 use rustc_ast::expand::StrippedCfgItem;
 use rustc_attr as attr;
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::svh::Svh;
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap};
@@ -18,12 +16,16 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
+use rustc_macros::{Decodable, Encodable, TyDecodable, TyEncodable};
 use rustc_macros::{MetadataDecodable, MetadataEncodable};
 use rustc_middle::metadata::ModChild;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
+use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
 use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
+use rustc_middle::middle::lib_features::FeatureStability;
 use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
 use rustc_middle::mir;
+use rustc_middle::trivially_parameterized_over_tcx;
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::{self, ReprOptions, Ty, UnusedGenericParams};
 use rustc_middle::ty::{DeducedParamAttrs, ParameterizedOverTcx, TyCtxt};
@@ -32,20 +34,14 @@
 use rustc_session::config::SymbolManglingVersion;
 use rustc_session::cstore::{CrateDepKind, ForeignModule, LinkagePreference, NativeLib};
 use rustc_span::edition::Edition;
-use rustc_span::hygiene::{ExpnIndex, MacroKind};
+use rustc_span::hygiene::{ExpnIndex, MacroKind, SyntaxContextData};
 use rustc_span::symbol::{Ident, Symbol};
 use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span};
 use rustc_target::abi::{FieldIdx, VariantIdx};
 use rustc_target::spec::{PanicStrategy, TargetTriple};
-
 use std::marker::PhantomData;
 use std::num::NonZero;
-
-use decoder::DecodeContext;
-pub(crate) use decoder::{CrateMetadata, CrateNumMap, MetadataBlob};
-use encoder::EncodeContext;
-pub use encoder::{encode_metadata, rendered_const, EncodedMetadata};
-use rustc_span::hygiene::SyntaxContextData;
+use table::TableBuilder;
 
 mod decoder;
 mod def_path_hash_map;
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index d1cdabc..ab0c598 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -28,6 +28,7 @@
 rustc_hir_pretty = { path = "../rustc_hir_pretty" }
 rustc_index = { path = "../rustc_index" }
 rustc_macros = { path = "../rustc_macros" }
+rustc_next_trait_solver = { path = "../rustc_next_trait_solver" }
 rustc_query_system = { path = "../rustc_query_system" }
 rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index 27d555d..f4d6193 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -50,6 +50,20 @@
 middle_cycle =
     a cycle occurred during layout computation
 
+middle_deprecated = use of deprecated {$kind} `{$path}`{$has_note ->
+        [true] : {$note}
+        *[other] {""}
+    }
+middle_deprecated_in_future = use of {$kind} `{$path}` that will be deprecated in a future Rust version{$has_note ->
+        [true] : {$note}
+        *[other] {""}
+    }
+middle_deprecated_in_version = use of {$kind} `{$path}` that will be deprecated in future version {$version}{$has_note ->
+        [true] : {$note}
+        *[other] {""}
+    }
+middle_deprecated_suggestion = replace the use of the deprecated {$kind}
+
 middle_drop_check_overflow =
     overflow while adding drop-check rules for {$ty}
     .note = overflowed on {$overflow_ty}
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index 1371926..7392eb6 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -61,7 +61,7 @@
             [] dtorck_constraint: rustc_middle::traits::query::DropckConstraint<'tcx>,
             [] candidate_step: rustc_middle::traits::query::CandidateStep<'tcx>,
             [] autoderef_bad_ty: rustc_middle::traits::query::MethodAutoderefBadTy<'tcx>,
-            [] canonical_goal_evaluation: rustc_middle::traits::solve::inspect::GoalEvaluationStep<'tcx>,
+            [] canonical_goal_evaluation: rustc_next_trait_solver::solve::inspect::GoalEvaluationStep<rustc_middle::ty::TyCtxt<'tcx>>,
             [] query_region_constraints: rustc_middle::infer::canonical::QueryRegionConstraints<'tcx>,
             [] type_op_subtype:
                 rustc_middle::infer::canonical::Canonical<'tcx,
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index c7aea13..f3f24f7 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -511,14 +511,14 @@
         self.body_const_context(self.enclosing_body_owner(hir_id)).is_some()
     }
 
-    /// Retrieves the `HirId` for `id`'s enclosing method, unless there's a
-    /// `while` or `loop` before reaching it, as block tail returns are not
-    /// available in them.
+    /// Retrieves the `HirId` for `id`'s enclosing function *if* the `id` block or return is
+    /// in the "tail" position of the function, in other words if it's likely to correspond
+    /// to the return type of the function.
     ///
     /// ```
     /// fn foo(x: usize) -> bool {
     ///     if x == 1 {
-    ///         true  // If `get_return_block` gets passed the `id` corresponding
+    ///         true  // If `get_fn_id_for_return_block` gets passed the `id` corresponding
     ///     } else {  // to this, it will return `foo`'s `HirId`.
     ///         false
     ///     }
@@ -528,12 +528,12 @@
     /// ```compile_fail,E0308
     /// fn foo(x: usize) -> bool {
     ///     loop {
-    ///         true  // If `get_return_block` gets passed the `id` corresponding
+    ///         true  // If `get_fn_id_for_return_block` gets passed the `id` corresponding
     ///     }         // to this, it will return `None`.
     ///     false
     /// }
     /// ```
-    pub fn get_return_block(self, id: HirId) -> Option<HirId> {
+    pub fn get_fn_id_for_return_block(self, id: HirId) -> Option<HirId> {
         let mut iter = self.parent_iter(id).peekable();
         let mut ignore_tail = false;
         if let Node::Expr(Expr { kind: ExprKind::Ret(_), .. }) = self.tcx.hir_node(id) {
@@ -549,6 +549,11 @@
                     Node::Block(Block { expr: None, .. }) => return None,
                     // The current node is not the tail expression of its parent.
                     Node::Block(Block { expr: Some(e), .. }) if hir_id != e.hir_id => return None,
+                    Node::Block(Block { expr: Some(e), .. })
+                        if matches!(e.kind, ExprKind::If(_, _, None)) =>
+                    {
+                        return None;
+                    }
                     _ => {}
                 }
             }
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index aee97d7..dba71d8 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -23,23 +23,20 @@
 
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::Lock;
-use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
-use rustc_type_ir::Canonical as IrCanonical;
-use rustc_type_ir::CanonicalVarInfo as IrCanonicalVarInfo;
+use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
+pub use rustc_type_ir as ir;
 pub use rustc_type_ir::{CanonicalTyVarKind, CanonicalVarKind};
 use smallvec::SmallVec;
 use std::collections::hash_map::Entry;
-use std::ops::Index;
 
 use crate::infer::MemberConstraint;
 use crate::mir::ConstraintCategory;
 use crate::ty::GenericArg;
-use crate::ty::{self, BoundVar, List, Region, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
+use crate::ty::{self, List, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
 
-pub type Canonical<'tcx, V> = IrCanonical<TyCtxt<'tcx>, V>;
-
-pub type CanonicalVarInfo<'tcx> = IrCanonicalVarInfo<TyCtxt<'tcx>>;
-
+pub type Canonical<'tcx, V> = ir::Canonical<TyCtxt<'tcx>, V>;
+pub type CanonicalVarInfo<'tcx> = ir::CanonicalVarInfo<TyCtxt<'tcx>>;
+pub type CanonicalVarValues<'tcx> = ir::CanonicalVarValues<TyCtxt<'tcx>>;
 pub type CanonicalVarInfos<'tcx> = &'tcx List<CanonicalVarInfo<'tcx>>;
 
 impl<'tcx> ty::TypeFoldable<TyCtxt<'tcx>> for CanonicalVarInfos<'tcx> {
@@ -51,74 +48,6 @@
     }
 }
 
-/// A set of values corresponding to the canonical variables from some
-/// `Canonical`. You can give these values to
-/// `canonical_value.instantiate` to instantiate them into the canonical
-/// value at the right places.
-///
-/// When you canonicalize a value `V`, you get back one of these
-/// vectors with the original values that were replaced by canonical
-/// variables. You will need to supply it later to instantiate the
-/// canonicalized query response.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TyDecodable, TyEncodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
-pub struct CanonicalVarValues<'tcx> {
-    pub var_values: ty::GenericArgsRef<'tcx>,
-}
-
-impl CanonicalVarValues<'_> {
-    pub fn is_identity(&self) -> bool {
-        self.var_values.iter().enumerate().all(|(bv, arg)| match arg.unpack() {
-            ty::GenericArgKind::Lifetime(r) => {
-                matches!(*r, ty::ReBound(ty::INNERMOST, br) if br.var.as_usize() == bv)
-            }
-            ty::GenericArgKind::Type(ty) => {
-                matches!(*ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var.as_usize() == bv)
-            }
-            ty::GenericArgKind::Const(ct) => {
-                matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.as_usize() == bv)
-            }
-        })
-    }
-
-    pub fn is_identity_modulo_regions(&self) -> bool {
-        let mut var = ty::BoundVar::ZERO;
-        for arg in self.var_values {
-            match arg.unpack() {
-                ty::GenericArgKind::Lifetime(r) => {
-                    if let ty::ReBound(ty::INNERMOST, br) = *r
-                        && var == br.var
-                    {
-                        var = var + 1;
-                    } else {
-                        // It's ok if this region var isn't unique
-                    }
-                }
-                ty::GenericArgKind::Type(ty) => {
-                    if let ty::Bound(ty::INNERMOST, bt) = *ty.kind()
-                        && var == bt.var
-                    {
-                        var = var + 1;
-                    } else {
-                        return false;
-                    }
-                }
-                ty::GenericArgKind::Const(ct) => {
-                    if let ty::ConstKind::Bound(ty::INNERMOST, bc) = ct.kind()
-                        && var == bc
-                    {
-                        var = var + 1;
-                    } else {
-                        return false;
-                    }
-                }
-            }
-        }
-
-        true
-    }
-}
-
 /// When we canonicalize a value to form a query, we wind up replacing
 /// various parts of it with canonical variables. This struct stores
 /// those replaced bits to remember for when we process the query
@@ -212,84 +141,12 @@
 }
 
 pub type QueryOutlivesConstraint<'tcx> =
-    (ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
+    (ty::OutlivesPredicate<'tcx, GenericArg<'tcx>>, ConstraintCategory<'tcx>);
 
 TrivialTypeTraversalImpls! {
     crate::infer::canonical::Certainty,
 }
 
-impl<'tcx> CanonicalVarValues<'tcx> {
-    // Given a list of canonical variables, construct a set of values which are
-    // the identity response.
-    pub fn make_identity(
-        tcx: TyCtxt<'tcx>,
-        infos: CanonicalVarInfos<'tcx>,
-    ) -> CanonicalVarValues<'tcx> {
-        CanonicalVarValues {
-            var_values: tcx.mk_args_from_iter(infos.iter().enumerate().map(
-                |(i, info)| -> ty::GenericArg<'tcx> {
-                    match info.kind {
-                        CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
-                            Ty::new_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i).into())
-                                .into()
-                        }
-                        CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
-                            let br = ty::BoundRegion {
-                                var: ty::BoundVar::from_usize(i),
-                                kind: ty::BrAnon,
-                            };
-                            ty::Region::new_bound(tcx, ty::INNERMOST, br).into()
-                        }
-                        CanonicalVarKind::Effect => ty::Const::new_bound(
-                            tcx,
-                            ty::INNERMOST,
-                            ty::BoundVar::from_usize(i),
-                            tcx.types.bool,
-                        )
-                        .into(),
-                        CanonicalVarKind::Const(_, ty)
-                        | CanonicalVarKind::PlaceholderConst(_, ty) => ty::Const::new_bound(
-                            tcx,
-                            ty::INNERMOST,
-                            ty::BoundVar::from_usize(i),
-                            ty,
-                        )
-                        .into(),
-                    }
-                },
-            )),
-        }
-    }
-
-    /// Creates dummy var values which should not be used in a
-    /// canonical response.
-    pub fn dummy() -> CanonicalVarValues<'tcx> {
-        CanonicalVarValues { var_values: ty::List::empty() }
-    }
-
-    #[inline]
-    pub fn len(&self) -> usize {
-        self.var_values.len()
-    }
-}
-
-impl<'a, 'tcx> IntoIterator for &'a CanonicalVarValues<'tcx> {
-    type Item = GenericArg<'tcx>;
-    type IntoIter = ::std::iter::Copied<::std::slice::Iter<'a, GenericArg<'tcx>>>;
-
-    fn into_iter(self) -> Self::IntoIter {
-        self.var_values.iter()
-    }
-}
-
-impl<'tcx> Index<BoundVar> for CanonicalVarValues<'tcx> {
-    type Output = GenericArg<'tcx>;
-
-    fn index(&self, value: BoundVar) -> &GenericArg<'tcx> {
-        &self.var_values[value.as_usize()]
-    }
-}
-
 #[derive(Default)]
 pub struct CanonicalParamEnvCache<'tcx> {
     map: Lock<
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index 04fd4c8..70437fd 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -22,46 +22,46 @@
 //!
 //! This API is completely unstable and subject to change.
 
+// tidy-alphabetical-start
+#![allow(internal_features)]
+#![allow(rustc::diagnostic_outside_of_impl)]
+#![allow(rustc::potential_query_instability)]
+#![allow(rustc::untranslatable_diagnostic)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
-#![feature(min_exhaustive_patterns)]
-#![feature(rustdoc_internals)]
 #![feature(allocator_api)]
 #![feature(array_windows)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(closure_track_caller)]
-#![feature(core_intrinsics)]
+#![feature(const_option)]
 #![feature(const_type_name)]
-#![feature(discriminant_kind)]
+#![feature(core_intrinsics)]
 #![feature(coroutines)]
-#![feature(stmt_expr_attributes)]
+#![feature(decl_macro)]
+#![feature(discriminant_kind)]
+#![feature(extern_types)]
+#![feature(extract_if)]
 #![feature(if_let_guard)]
+#![feature(intra_doc_pointers)]
 #![feature(iter_from_coroutine)]
+#![feature(let_chains)]
+#![feature(macro_metavar_expr)]
+#![feature(min_exhaustive_patterns)]
+#![feature(min_specialization)]
 #![feature(negative_impls)]
 #![feature(never_type)]
-#![feature(extern_types)]
 #![feature(new_uninit)]
-#![feature(let_chains)]
-#![feature(min_specialization)]
-#![feature(trusted_len)]
-#![feature(type_alias_impl_trait)]
-#![feature(strict_provenance)]
-#![feature(rustc_attrs)]
-#![feature(control_flow_enum)]
-#![feature(trait_upcasting)]
-#![feature(try_blocks)]
-#![feature(decl_macro)]
-#![feature(extract_if)]
-#![feature(intra_doc_pointers)]
-#![feature(yeet_expr)]
-#![feature(const_option)]
 #![feature(ptr_alignment_type)]
-#![feature(macro_metavar_expr)]
-#![allow(internal_features)]
-#![allow(rustc::potential_query_instability)]
-#![allow(rustc::diagnostic_outside_of_impl)]
-#![allow(rustc::untranslatable_diagnostic)]
+#![feature(rustc_attrs)]
+#![feature(rustdoc_internals)]
+#![feature(strict_provenance)]
+#![feature(trait_upcasting)]
+#![feature(trusted_len)]
+#![feature(try_blocks)]
+#![feature(type_alias_impl_trait)]
+#![feature(yeet_expr)]
+// tidy-alphabetical-end
 
 #[macro_use]
 extern crate tracing;
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index f70ef51..817ac59 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -57,7 +57,7 @@
 macro_rules! TrivialLiftImpls {
     ($($ty:ty),+ $(,)?) => {
         $(
-            impl<'tcx> $crate::ty::Lift<'tcx> for $ty {
+            impl<'tcx> $crate::ty::Lift<$crate::ty::TyCtxt<'tcx>> for $ty {
                 type Lifted = Self;
                 fn lift_to_tcx(self, _: $crate::ty::TyCtxt<'tcx>) -> Option<Self> {
                     Some(self)
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index 67bd53f..e5df057 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -9,15 +9,15 @@
     self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability,
 };
 use rustc_data_structures::unord::UnordMap;
-use rustc_errors::{Applicability, Diag};
+use rustc_errors::{Applicability, Diag, EmissionGuarantee};
 use rustc_feature::GateIssue;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId, LocalDefIdMap};
 use rustc_hir::{self as hir, HirId};
-use rustc_macros::{Decodable, Encodable, HashStable};
+use rustc_macros::{Decodable, Encodable, HashStable, Subdiagnostic};
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_session::lint::builtin::{DEPRECATED, DEPRECATED_IN_FUTURE, SOFT_UNSTABLE};
-use rustc_session::lint::{BuiltinLintDiag, Level, Lint, LintBuffer};
+use rustc_session::lint::{BuiltinLintDiag, DeprecatedSinceKind, Level, Lint, LintBuffer};
 use rustc_session::parse::feature_err_issue;
 use rustc_session::Session;
 use rustc_span::symbol::{sym, Symbol};
@@ -125,90 +125,107 @@
     }
 }
 
-pub fn deprecation_suggestion(
-    diag: &mut Diag<'_, ()>,
-    kind: &str,
-    suggestion: Option<Symbol>,
-    span: Span,
-) {
-    if let Some(suggestion) = suggestion {
-        diag.span_suggestion_verbose(
-            span,
-            format!("replace the use of the deprecated {kind}"),
-            suggestion,
-            Applicability::MachineApplicable,
-        );
-    }
-}
-
 fn deprecation_lint(is_in_effect: bool) -> &'static Lint {
     if is_in_effect { DEPRECATED } else { DEPRECATED_IN_FUTURE }
 }
 
-fn deprecation_message(
-    is_in_effect: bool,
-    since: DeprecatedSince,
-    note: Option<Symbol>,
-    kind: &str,
-    path: &str,
-) -> String {
-    let message = if is_in_effect {
-        format!("use of deprecated {kind} `{path}`")
+#[derive(Subdiagnostic)]
+#[suggestion(
+    middle_deprecated_suggestion,
+    code = "{suggestion}",
+    style = "verbose",
+    applicability = "machine-applicable"
+)]
+pub struct DeprecationSuggestion {
+    #[primary_span]
+    pub span: Span,
+
+    pub kind: String,
+    pub suggestion: Symbol,
+}
+
+pub struct Deprecated {
+    pub sub: Option<DeprecationSuggestion>,
+
+    // FIXME: make this translatable
+    pub kind: String,
+    pub path: String,
+    pub note: Option<Symbol>,
+    pub since_kind: DeprecatedSinceKind,
+}
+
+impl<'a, G: EmissionGuarantee> rustc_errors::LintDiagnostic<'a, G> for Deprecated {
+    fn decorate_lint<'b>(self, diag: &'b mut Diag<'a, G>) {
+        diag.arg("kind", self.kind);
+        diag.arg("path", self.path);
+        if let DeprecatedSinceKind::InVersion(version) = self.since_kind {
+            diag.arg("version", version);
+        }
+        if let Some(note) = self.note {
+            diag.arg("has_note", true);
+            diag.arg("note", note);
+        } else {
+            diag.arg("has_note", false);
+        }
+        if let Some(sub) = self.sub {
+            diag.subdiagnostic(diag.dcx, sub);
+        }
+    }
+
+    fn msg(&self) -> rustc_errors::DiagMessage {
+        match &self.since_kind {
+            DeprecatedSinceKind::InEffect => crate::fluent_generated::middle_deprecated,
+            DeprecatedSinceKind::InFuture => crate::fluent_generated::middle_deprecated_in_future,
+            DeprecatedSinceKind::InVersion(_) => {
+                crate::fluent_generated::middle_deprecated_in_version
+            }
+        }
+    }
+}
+
+fn deprecated_since_kind(is_in_effect: bool, since: DeprecatedSince) -> DeprecatedSinceKind {
+    if is_in_effect {
+        DeprecatedSinceKind::InEffect
     } else {
         match since {
-            DeprecatedSince::RustcVersion(version) => format!(
-                "use of {kind} `{path}` that will be deprecated in future version {version}"
-            ),
-            DeprecatedSince::Future => {
-                format!("use of {kind} `{path}` that will be deprecated in a future Rust version")
+            DeprecatedSince::RustcVersion(version) => {
+                DeprecatedSinceKind::InVersion(version.to_string())
             }
+            DeprecatedSince::Future => DeprecatedSinceKind::InFuture,
             DeprecatedSince::NonStandard(_)
             | DeprecatedSince::Unspecified
             | DeprecatedSince::Err => {
                 unreachable!("this deprecation is always in effect; {since:?}")
             }
         }
-    };
-
-    match note {
-        Some(reason) => format!("{message}: {reason}"),
-        None => message,
     }
 }
 
-pub fn deprecation_message_and_lint(
-    depr: &Deprecation,
-    kind: &str,
-    path: &str,
-) -> (String, &'static Lint) {
-    let is_in_effect = depr.is_in_effect();
-    (
-        deprecation_message(is_in_effect, depr.since, depr.note, kind, path),
-        deprecation_lint(is_in_effect),
-    )
-}
-
-pub fn early_report_deprecation(
+pub fn early_report_macro_deprecation(
     lint_buffer: &mut LintBuffer,
-    message: String,
-    suggestion: Option<Symbol>,
-    lint: &'static Lint,
+    depr: &Deprecation,
     span: Span,
     node_id: NodeId,
+    path: String,
 ) {
     if span.in_derive_expansion() {
         return;
     }
 
-    let diag = BuiltinLintDiag::DeprecatedMacro(suggestion, span);
-    lint_buffer.buffer_lint_with_diagnostic(lint, node_id, span, message, diag);
+    let is_in_effect = depr.is_in_effect();
+    let diag = BuiltinLintDiag::DeprecatedMacro {
+        suggestion: depr.suggestion,
+        suggestion_span: span,
+        note: depr.note,
+        path,
+        since_kind: deprecated_since_kind(is_in_effect, depr.since.clone()),
+    };
+    lint_buffer.buffer_lint(deprecation_lint(is_in_effect), node_id, span, diag);
 }
 
 fn late_report_deprecation(
     tcx: TyCtxt<'_>,
-    message: String,
-    suggestion: Option<Symbol>,
-    lint: &'static Lint,
+    depr: &Deprecation,
     span: Span,
     method_span: Option<Span>,
     hir_id: HirId,
@@ -217,13 +234,26 @@
     if span.in_derive_expansion() {
         return;
     }
+
+    let def_path = with_no_trimmed_paths!(tcx.def_path_str(def_id));
+    let def_kind = tcx.def_descr(def_id);
+    let is_in_effect = depr.is_in_effect();
+
     let method_span = method_span.unwrap_or(span);
-    tcx.node_span_lint(lint, hir_id, method_span, message, |diag| {
-        if let hir::Node::Expr(_) = tcx.hir_node(hir_id) {
-            let kind = tcx.def_descr(def_id);
-            deprecation_suggestion(diag, kind, suggestion, method_span);
-        }
-    });
+    let suggestion =
+        if let hir::Node::Expr(_) = tcx.hir_node(hir_id) { depr.suggestion } else { None };
+    let diag = Deprecated {
+        sub: suggestion.map(|suggestion| DeprecationSuggestion {
+            span: method_span,
+            kind: def_kind.to_owned(),
+            suggestion,
+        }),
+        kind: def_kind.to_owned(),
+        path: def_path,
+        note: depr.note,
+        since_kind: deprecated_since_kind(is_in_effect, depr.since),
+    };
+    tcx.emit_node_span_lint(deprecation_lint(is_in_effect), hir_id, method_span, diag);
 }
 
 /// Result of `TyCtxt::eval_stability`.
@@ -352,28 +382,9 @@
                     // Calculating message for lint involves calling `self.def_path_str`.
                     // Which by default to calculate visible path will invoke expensive `visible_parent_map` query.
                     // So we skip message calculation altogether, if lint is allowed.
-                    let is_in_effect = depr_attr.is_in_effect();
-                    let lint = deprecation_lint(is_in_effect);
+                    let lint = deprecation_lint(depr_attr.is_in_effect());
                     if self.lint_level_at_node(lint, id).0 != Level::Allow {
-                        let def_path = with_no_trimmed_paths!(self.def_path_str(def_id));
-                        let def_kind = self.def_descr(def_id);
-
-                        late_report_deprecation(
-                            self,
-                            deprecation_message(
-                                is_in_effect,
-                                depr_attr.since,
-                                depr_attr.note,
-                                def_kind,
-                                &def_path,
-                            ),
-                            depr_attr.suggestion,
-                            lint,
-                            span,
-                            method_span,
-                            id,
-                            def_id,
-                        );
+                        late_report_deprecation(self, depr_attr, span, method_span, id, def_id);
                     }
                 }
             };
diff --git a/compiler/rustc_middle/src/mir/coverage.rs b/compiler/rustc_middle/src/mir/coverage.rs
index 477303e..4155c61 100644
--- a/compiler/rustc_middle/src/mir/coverage.rs
+++ b/compiler/rustc_middle/src/mir/coverage.rs
@@ -129,17 +129,11 @@
     /// Marks the point in MIR control flow represented by a evaluated condition.
     ///
     /// This is eventually lowered to `llvm.instrprof.mcdc.condbitmap.update` in LLVM IR.
-    ///
-    /// If this statement does not survive MIR optimizations, the condition would never be
-    /// taken as evaluated.
     CondBitmapUpdate { id: ConditionId, value: bool, decision_depth: u16 },
 
     /// Marks the point in MIR control flow represented by a evaluated decision.
     ///
     /// This is eventually lowered to `llvm.instrprof.mcdc.tvbitmap.update` in LLVM IR.
-    ///
-    /// If this statement does not survive MIR optimizations, the decision would never be
-    /// taken as evaluated.
     TestVectorBitmapUpdate { bitmap_idx: u32, decision_depth: u16 },
 }
 
@@ -187,8 +181,8 @@
     }
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
-#[derive(TypeFoldable, TypeVisitable)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable)]
+#[derive(TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)]
 pub enum Op {
     Subtract,
     Add,
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 3832414..6e152cb 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -188,8 +188,9 @@
 }
 
 /// Error information for when the program we executed turned out not to actually be a valid
-/// program. This cannot happen in stand-alone Miri, but it can happen during CTFE/ConstProp
-/// where we work on generic code or execution does not have all information available.
+/// program. This cannot happen in stand-alone Miri (except for layout errors that are only detect
+/// during monomorphization), but it can happen during CTFE/ConstProp where we work on generic code
+/// or execution does not have all information available.
 #[derive(Debug)]
 pub enum InvalidProgramInfo<'tcx> {
     /// Resolution can fail if we are in a too generic context.
@@ -507,7 +508,7 @@
 /// Miri engine, e.g., CTFE does not support dereferencing pointers at integral addresses.
 #[derive(Debug)]
 pub enum UnsupportedOpInfo {
-    /// Free-form case. Only for errors that are never caught!
+    /// Free-form case. Only for errors that are never caught! Used by Miri.
     // FIXME still use translatable diagnostics
     Unsupported(String),
     /// Unsized local variables.
@@ -592,3 +593,117 @@
         )
     }
 }
+
+// Macros for constructing / throwing `InterpError`
+#[macro_export]
+macro_rules! err_unsup {
+    ($($tt:tt)*) => {
+        $crate::mir::interpret::InterpError::Unsupported(
+            $crate::mir::interpret::UnsupportedOpInfo::$($tt)*
+        )
+    };
+}
+
+#[macro_export]
+macro_rules! err_unsup_format {
+    ($($tt:tt)*) => { $crate::err_unsup!(Unsupported(format!($($tt)*))) };
+}
+
+#[macro_export]
+macro_rules! err_inval {
+    ($($tt:tt)*) => {
+        $crate::mir::interpret::InterpError::InvalidProgram(
+            $crate::mir::interpret::InvalidProgramInfo::$($tt)*
+        )
+    };
+}
+
+#[macro_export]
+macro_rules! err_ub {
+    ($($tt:tt)*) => {
+        $crate::mir::interpret::InterpError::UndefinedBehavior(
+            $crate::mir::interpret::UndefinedBehaviorInfo::$($tt)*
+        )
+    };
+}
+
+#[macro_export]
+macro_rules! err_ub_format {
+    ($($tt:tt)*) => { $crate::err_ub!(Ub(format!($($tt)*))) };
+}
+
+#[macro_export]
+macro_rules! err_ub_custom {
+    ($msg:expr $(, $($name:ident = $value:expr),* $(,)?)?) => {{
+        $(
+            let ($($name,)*) = ($($value,)*);
+        )?
+        $crate::err_ub!(Custom(
+            $crate::error::CustomSubdiagnostic {
+                msg: || $msg,
+                add_args: Box::new(move |mut set_arg| {
+                    $($(
+                        set_arg(stringify!($name).into(), rustc_errors::IntoDiagArg::into_diag_arg($name));
+                    )*)?
+                })
+            }
+        ))
+    }};
+}
+
+#[macro_export]
+macro_rules! err_exhaust {
+    ($($tt:tt)*) => {
+        $crate::mir::interpret::InterpError::ResourceExhaustion(
+            $crate::mir::interpret::ResourceExhaustionInfo::$($tt)*
+        )
+    };
+}
+
+#[macro_export]
+macro_rules! err_machine_stop {
+    ($($tt:tt)*) => {
+        $crate::mir::interpret::InterpError::MachineStop(Box::new($($tt)*))
+    };
+}
+
+// In the `throw_*` macros, avoid `return` to make them work with `try {}`.
+#[macro_export]
+macro_rules! throw_unsup {
+    ($($tt:tt)*) => { do yeet $crate::err_unsup!($($tt)*) };
+}
+
+#[macro_export]
+macro_rules! throw_unsup_format {
+    ($($tt:tt)*) => { do yeet $crate::err_unsup_format!($($tt)*) };
+}
+
+#[macro_export]
+macro_rules! throw_inval {
+    ($($tt:tt)*) => { do yeet $crate::err_inval!($($tt)*) };
+}
+
+#[macro_export]
+macro_rules! throw_ub {
+    ($($tt:tt)*) => { do yeet $crate::err_ub!($($tt)*) };
+}
+
+#[macro_export]
+macro_rules! throw_ub_format {
+    ($($tt:tt)*) => { do yeet $crate::err_ub_format!($($tt)*) };
+}
+
+#[macro_export]
+macro_rules! throw_ub_custom {
+    ($($tt:tt)*) => { do yeet $crate::err_ub_custom!($($tt)*) };
+}
+
+#[macro_export]
+macro_rules! throw_exhaust {
+    ($($tt:tt)*) => { do yeet $crate::err_exhaust!($($tt)*) };
+}
+
+#[macro_export]
+macro_rules! throw_machine_stop {
+    ($($tt:tt)*) => { do yeet $crate::err_machine_stop!($($tt)*) };
+}
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index ee3cdf3..739b141 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -1,120 +1,9 @@
 //! An interpreter for MIR used in CTFE and by miri.
 
-#[macro_export]
-macro_rules! err_unsup {
-    ($($tt:tt)*) => {
-        $crate::mir::interpret::InterpError::Unsupported(
-            $crate::mir::interpret::UnsupportedOpInfo::$($tt)*
-        )
-    };
-}
-
-#[macro_export]
-macro_rules! err_unsup_format {
-    ($($tt:tt)*) => { err_unsup!(Unsupported(format!($($tt)*))) };
-}
-
-#[macro_export]
-macro_rules! err_inval {
-    ($($tt:tt)*) => {
-        $crate::mir::interpret::InterpError::InvalidProgram(
-            $crate::mir::interpret::InvalidProgramInfo::$($tt)*
-        )
-    };
-}
-
-#[macro_export]
-macro_rules! err_ub {
-    ($($tt:tt)*) => {
-        $crate::mir::interpret::InterpError::UndefinedBehavior(
-            $crate::mir::interpret::UndefinedBehaviorInfo::$($tt)*
-        )
-    };
-}
-
-#[macro_export]
-macro_rules! err_ub_format {
-    ($($tt:tt)*) => { err_ub!(Ub(format!($($tt)*))) };
-}
-
-#[macro_export]
-macro_rules! err_exhaust {
-    ($($tt:tt)*) => {
-        $crate::mir::interpret::InterpError::ResourceExhaustion(
-            $crate::mir::interpret::ResourceExhaustionInfo::$($tt)*
-        )
-    };
-}
-
-#[macro_export]
-macro_rules! err_machine_stop {
-    ($($tt:tt)*) => {
-        $crate::mir::interpret::InterpError::MachineStop(Box::new($($tt)*))
-    };
-}
-
-// In the `throw_*` macros, avoid `return` to make them work with `try {}`.
-#[macro_export]
-macro_rules! throw_unsup {
-    ($($tt:tt)*) => { do yeet err_unsup!($($tt)*) };
-}
-
-#[macro_export]
-macro_rules! throw_unsup_format {
-    ($($tt:tt)*) => { throw_unsup!(Unsupported(format!($($tt)*))) };
-}
-
-#[macro_export]
-macro_rules! throw_inval {
-    ($($tt:tt)*) => { do yeet err_inval!($($tt)*) };
-}
-
-#[macro_export]
-macro_rules! throw_ub {
-    ($($tt:tt)*) => { do yeet err_ub!($($tt)*) };
-}
-
-#[macro_export]
-macro_rules! throw_ub_format {
-    ($($tt:tt)*) => { throw_ub!(Ub(format!($($tt)*))) };
-}
-
-#[macro_export]
-macro_rules! throw_exhaust {
-    ($($tt:tt)*) => { do yeet err_exhaust!($($tt)*) };
-}
-
-#[macro_export]
-macro_rules! throw_machine_stop {
-    ($($tt:tt)*) => { do yeet err_machine_stop!($($tt)*) };
-}
-
-#[macro_export]
-macro_rules! err_ub_custom {
-    ($msg:expr $(, $($name:ident = $value:expr),* $(,)?)?) => {{
-        $(
-            let ($($name,)*) = ($($value,)*);
-        )?
-        err_ub!(Custom(
-            rustc_middle::error::CustomSubdiagnostic {
-                msg: || $msg,
-                add_args: Box::new(move |mut set_arg| {
-                    $($(
-                        set_arg(stringify!($name).into(), rustc_errors::IntoDiagArg::into_diag_arg($name));
-                    )*)?
-                })
-            }
-        ))
-    }};
-}
-
-#[macro_export]
-macro_rules! throw_ub_custom {
-    ($($tt:tt)*) => { do yeet err_ub_custom!($($tt)*) };
-}
+#[macro_use]
+mod error;
 
 mod allocation;
-mod error;
 mod pointer;
 mod queries;
 mod value;
@@ -125,10 +14,11 @@
 use std::num::NonZero;
 use std::sync::atomic::{AtomicU32, Ordering};
 
+use smallvec::{smallvec, SmallVec};
+
 use rustc_ast::LitKind;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::sync::{HashMapExt, Lock};
-use rustc_data_structures::tiny_list::TinyList;
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
@@ -149,6 +39,12 @@
     ScalarSizeMismatch, UndefinedBehaviorInfo, UnsupportedOpInfo, ValidationErrorInfo,
     ValidationErrorKind,
 };
+// Also make the error macros available from this module.
+pub use {
+    err_exhaust, err_inval, err_machine_stop, err_ub, err_ub_custom, err_ub_format, err_unsup,
+    err_unsup_format, throw_exhaust, throw_inval, throw_machine_stop, throw_ub, throw_ub_custom,
+    throw_ub_format, throw_unsup, throw_unsup_format,
+};
 
 pub use self::value::Scalar;
 
@@ -266,8 +162,8 @@
 #[derive(Clone)]
 enum State {
     Empty,
-    InProgressNonAlloc(TinyList<DecodingSessionId>),
-    InProgress(TinyList<DecodingSessionId>, AllocId),
+    InProgressNonAlloc(SmallVec<[DecodingSessionId; 1]>),
+    InProgress(SmallVec<[DecodingSessionId; 1]>, AllocId),
     Done(AllocId),
 }
 
@@ -337,8 +233,7 @@
                             // If this is an allocation, we need to reserve an
                             // `AllocId` so we can decode cyclic graphs.
                             let alloc_id = decoder.interner().reserve_alloc_id();
-                            *entry =
-                                State::InProgress(TinyList::new_single(self.session_id), alloc_id);
+                            *entry = State::InProgress(smallvec![self.session_id], alloc_id);
                             Some(alloc_id)
                         }
                         AllocDiscriminant::Fn
@@ -346,8 +241,7 @@
                         | AllocDiscriminant::VTable => {
                             // Fns and statics cannot be cyclic, and their `AllocId`
                             // is determined later by interning.
-                            *entry =
-                                State::InProgressNonAlloc(TinyList::new_single(self.session_id));
+                            *entry = State::InProgressNonAlloc(smallvec![self.session_id]);
                             None
                         }
                     }
@@ -357,7 +251,7 @@
                         bug!("this should be unreachable");
                     } else {
                         // Start decoding concurrently.
-                        sessions.insert(self.session_id);
+                        sessions.push(self.session_id);
                         None
                     }
                 }
@@ -367,7 +261,7 @@
                         return alloc_id;
                     } else {
                         // Start decoding concurrently.
-                        sessions.insert(self.session_id);
+                        sessions.push(self.session_id);
                         Some(alloc_id)
                     }
                 }
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 5aaa1c3..7e8598b 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -971,9 +971,6 @@
                 with_no_trimmed_paths!(write!(fmt, "{place:?} as {ty} ({kind:?})"))
             }
             BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{op:?}({a:?}, {b:?})"),
-            CheckedBinaryOp(ref op, box (ref a, ref b)) => {
-                write!(fmt, "Checked{op:?}({a:?}, {b:?})")
-            }
             UnaryOp(ref op, ref a) => write!(fmt, "{op:?}({a:?})"),
             Discriminant(ref place) => write!(fmt, "discriminant({place:?})"),
             NullaryOp(ref op, ref t) => {
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index 9a7af61..9d70231 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -362,8 +362,4 @@
     /// InstrumentCoverage MIR pass, if the highest-numbered counter increments
     /// were removed by MIR optimizations.
     pub max_counter_id: mir::coverage::CounterId,
-
-    /// Coverage codegen for mcdc needs to know the size of the global bitmap so that it can
-    /// set the `bytemap-bytes` argument of the `llvm.instrprof.mcdc.tvbitmap.update` intrinsic.
-    pub mcdc_bitmap_bytes: u32,
 }
diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs
index 375f1f1..4d9a931 100644
--- a/compiler/rustc_middle/src/mir/statement.rs
+++ b/compiler/rustc_middle/src/mir/statement.rs
@@ -438,7 +438,6 @@
                 _,
             )
             | Rvalue::BinaryOp(_, _)
-            | Rvalue::CheckedBinaryOp(_, _)
             | Rvalue::NullaryOp(_, _)
             | Rvalue::UnaryOp(_, _)
             | Rvalue::Discriminant(_)
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 4278ce8..2b28496 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -1295,18 +1295,12 @@
     ///   truncated as needed.
     /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching
     ///   types and return a value of that type.
+    /// * The `FooWithOverflow` are like the `Foo`, but returning `(T, bool)` instead of just `T`,
+    ///   where the `bool` is true if the result is not equal to the infinite-precision result.
     /// * The remaining operations accept signed integers, unsigned integers, or floats with
     ///   matching types and return a value of that type.
     BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
 
-    /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition.
-    ///
-    /// For addition, subtraction, and multiplication on integers the error condition is set when
-    /// the infinite precision result would not be equal to the actual result.
-    ///
-    /// Other combinations of types and operators are unsupported.
-    CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
-
     /// Computes a value as described by the operation.
     NullaryOp(NullOp<'tcx>, Ty<'tcx>),
 
@@ -1449,14 +1443,23 @@
     Add,
     /// Like `Add`, but with UB on overflow.  (Integers only.)
     AddUnchecked,
+    /// Like `Add`, but returns `(T, bool)` of both the wrapped result
+    /// and a bool indicating whether it overflowed.
+    AddWithOverflow,
     /// The `-` operator (subtraction)
     Sub,
     /// Like `Sub`, but with UB on overflow.  (Integers only.)
     SubUnchecked,
+    /// Like `Sub`, but returns `(T, bool)` of both the wrapped result
+    /// and a bool indicating whether it overflowed.
+    SubWithOverflow,
     /// The `*` operator (multiplication)
     Mul,
     /// Like `Mul`, but with UB on overflow.  (Integers only.)
     MulUnchecked,
+    /// Like `Mul`, but returns `(T, bool)` of both the wrapped result
+    /// and a bool indicating whether it overflowed.
+    MulWithOverflow,
     /// The `/` operator (division)
     ///
     /// For integer types, division by zero is UB, as is `MIN / -1` for signed.
@@ -1480,13 +1483,17 @@
     BitOr,
     /// The `<<` operator (shift left)
     ///
-    /// The offset is truncated to the size of the first operand and made unsigned before shifting.
+    /// The offset is (uniquely) determined as follows:
+    /// - it is "equal modulo LHS::BITS" to the RHS
+    /// - it is in the range `0..LHS::BITS`
     Shl,
     /// Like `Shl`, but is UB if the RHS >= LHS::BITS or RHS < 0
     ShlUnchecked,
     /// The `>>` operator (shift right)
     ///
-    /// The offset is truncated to the size of the first operand and made unsigned before shifting.
+    /// The offset is (uniquely) determined as follows:
+    /// - it is "equal modulo LHS::BITS" to the RHS
+    /// - it is in the range `0..LHS::BITS`
     ///
     /// This is an arithmetic shift if the LHS is signed
     /// and a logical shift if the LHS is unsigned.
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 3881723..e1ae2e0 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -78,13 +78,9 @@
         }
         let answer = match *elem {
             ProjectionElem::Deref => {
-                let ty = self
-                    .ty
-                    .builtin_deref(true)
-                    .unwrap_or_else(|| {
-                        bug!("deref projection of non-dereferenceable ty {:?}", self)
-                    })
-                    .ty;
+                let ty = self.ty.builtin_deref(true).unwrap_or_else(|| {
+                    bug!("deref projection of non-dereferenceable ty {:?}", self)
+                });
                 PlaceTy::from_ty(ty)
             }
             ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => {
@@ -183,12 +179,6 @@
                 let rhs_ty = rhs.ty(local_decls, tcx);
                 op.ty(tcx, lhs_ty, rhs_ty)
             }
-            Rvalue::CheckedBinaryOp(op, box (ref lhs, ref rhs)) => {
-                let lhs_ty = lhs.ty(local_decls, tcx);
-                let rhs_ty = rhs.ty(local_decls, tcx);
-                let ty = op.ty(tcx, lhs_ty, rhs_ty);
-                Ty::new_tup(tcx, &[ty, tcx.types.bool])
-            }
             Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
             Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
             Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
@@ -267,6 +257,11 @@
                 assert_eq!(lhs_ty, rhs_ty);
                 lhs_ty
             }
+            &BinOp::AddWithOverflow | &BinOp::SubWithOverflow | &BinOp::MulWithOverflow => {
+                // these should be integers of the same size.
+                assert_eq!(lhs_ty, rhs_ty);
+                Ty::new_tup(tcx, &[lhs_ty, tcx.types.bool])
+            }
             &BinOp::Shl
             | &BinOp::ShlUnchecked
             | &BinOp::Shr
@@ -319,6 +314,9 @@
             BinOp::Le => hir::BinOpKind::Le,
             BinOp::Ge => hir::BinOpKind::Ge,
             BinOp::Cmp
+            | BinOp::AddWithOverflow
+            | BinOp::SubWithOverflow
+            | BinOp::MulWithOverflow
             | BinOp::AddUnchecked
             | BinOp::SubUnchecked
             | BinOp::MulUnchecked
@@ -329,4 +327,24 @@
             }
         }
     }
+
+    /// If this is a `FooWithOverflow`, return `Some(Foo)`.
+    pub fn overflowing_to_wrapping(self) -> Option<BinOp> {
+        Some(match self {
+            BinOp::AddWithOverflow => BinOp::Add,
+            BinOp::SubWithOverflow => BinOp::Sub,
+            BinOp::MulWithOverflow => BinOp::Mul,
+            _ => return None,
+        })
+    }
+
+    /// If this is a `Foo`, return `Some(FooWithOverflow)`.
+    pub fn wrapping_to_overflowing(self) -> Option<BinOp> {
+        Some(match self {
+            BinOp::Add => BinOp::AddWithOverflow,
+            BinOp::Sub => BinOp::SubWithOverflow,
+            BinOp::Mul => BinOp::MulWithOverflow,
+            _ => return None,
+        })
+    }
 }
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index d97abc3..8901fd4 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -696,8 +696,7 @@
                         self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
                     }
 
-                    Rvalue::BinaryOp(_bin_op, box(lhs, rhs))
-                    | Rvalue::CheckedBinaryOp(_bin_op, box(lhs, rhs)) => {
+                    Rvalue::BinaryOp(_bin_op, box(lhs, rhs)) => {
                         self.visit_operand(lhs, location);
                         self.visit_operand(rhs, location);
                     }
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 1ae037e..62e71c4 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -9,7 +9,6 @@
 mod structural_impls;
 pub mod util;
 
-use crate::infer::canonical::Canonical;
 use crate::mir::ConstraintCategory;
 use crate::ty::abstract_const::NotConstEvaluatable;
 use crate::ty::GenericArgsRef;
@@ -32,8 +31,8 @@
 use std::hash::{Hash, Hasher};
 
 pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache};
-
-pub use self::ObligationCauseCode::*;
+// FIXME: Remove this import and import via `solve::`
+pub use rustc_next_trait_solver::solve::BuiltinImplSource;
 
 /// Depending on the stage of compilation, we want projection to be
 /// more or less conservative.
@@ -129,7 +128,7 @@
     }
 
     pub fn misc(span: Span, body_id: LocalDefId) -> ObligationCause<'tcx> {
-        ObligationCause::new(span, body_id, MiscObligation)
+        ObligationCause::new(span, body_id, ObligationCauseCode::Misc)
     }
 
     #[inline(always)]
@@ -167,7 +166,7 @@
     pub fn derived_cause(
         mut self,
         parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
-        variant: impl FnOnce(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>,
+        variant: impl FnOnce(DerivedCause<'tcx>) -> ObligationCauseCode<'tcx>,
     ) -> ObligationCause<'tcx> {
         /*!
          * Creates a cause for obligations that are derived from
@@ -182,15 +181,14 @@
         // NOTE(flaper87): As of now, it keeps track of the whole error
         // chain. Ideally, we should have a way to configure this either
         // by using -Z verbose-internals or just a CLI argument.
-        self.code =
-            variant(DerivedObligationCause { parent_trait_pred, parent_code: self.code }).into();
+        self.code = variant(DerivedCause { parent_trait_pred, parent_code: self.code }).into();
         self
     }
 
     pub fn to_constraint_category(&self) -> ConstraintCategory<'tcx> {
         match self.code() {
-            MatchImpl(cause, _) => cause.to_constraint_category(),
-            AscribeUserTypeProvePredicate(predicate_span) => {
+            ObligationCauseCode::MatchImpl(cause, _) => cause.to_constraint_category(),
+            ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span) => {
                 ConstraintCategory::Predicate(*predicate_span)
             }
             _ => ConstraintCategory::BoringNoLocation,
@@ -209,7 +207,7 @@
 #[derive(Clone, PartialEq, Eq, Default, HashStable)]
 #[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)]
 pub struct InternedObligationCauseCode<'tcx> {
-    /// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of
+    /// `None` for `ObligationCauseCode::Misc` (a common case, occurs ~60% of
     /// the time). `Some` otherwise.
     code: Option<Lrc<ObligationCauseCode<'tcx>>>,
 }
@@ -225,11 +223,7 @@
     #[inline(always)]
     fn into(self) -> InternedObligationCauseCode<'tcx> {
         InternedObligationCauseCode {
-            code: if let ObligationCauseCode::MiscObligation = self {
-                None
-            } else {
-                Some(Lrc::new(self))
-            },
+            code: if let ObligationCauseCode::Misc = self { None } else { Some(Lrc::new(self)) },
         }
     }
 }
@@ -238,7 +232,7 @@
     type Target = ObligationCauseCode<'tcx>;
 
     fn deref(&self) -> &Self::Target {
-        self.code.as_deref().unwrap_or(&ObligationCauseCode::MiscObligation)
+        self.code.as_deref().unwrap_or(&ObligationCauseCode::Misc)
     }
 }
 
@@ -246,7 +240,7 @@
 #[derive(TypeVisitable, TypeFoldable)]
 pub enum ObligationCauseCode<'tcx> {
     /// Not well classified or should be obvious from the span.
-    MiscObligation,
+    Misc,
 
     /// A slice or array is WF only if `T: Sized`.
     SliceOrArrayElem,
@@ -254,22 +248,15 @@
     /// A tuple is WF only if its middle elements are `Sized`.
     TupleElem,
 
-    /// Must satisfy all of the where-clause predicates of the
-    /// given item.
-    ItemObligation(DefId),
+    /// Represents a clause that comes from a specific item.
+    /// The span corresponds to the clause.
+    WhereClause(DefId, Span),
 
-    /// Like `ItemObligation`, but carries the span of the
-    /// predicate when it can be identified.
-    BindingObligation(DefId, Span),
-
-    /// Like `ItemObligation`, but carries the `HirId` of the
-    /// expression that caused the obligation, and the `usize`
-    /// indicates exactly which predicate it is in the list of
-    /// instantiated predicates.
-    ExprItemObligation(DefId, HirId, usize),
-
-    /// Combines `ExprItemObligation` and `BindingObligation`.
-    ExprBindingObligation(DefId, Span, HirId, usize),
+    /// Like `WhereClause`, but also identifies the expression
+    /// which requires the `where` clause to be proven, and also
+    /// identifies the index of the predicate in the `predicates_of`
+    /// list of the item.
+    WhereClauseInExpr(DefId, Span, HirId, usize),
 
     /// A type like `&'a T` is WF only if `T: 'a`.
     ReferenceOutlivesReferent(Ty<'tcx>),
@@ -333,16 +320,18 @@
 
     /// Derived obligation (i.e. theoretical `where` clause) on a built-in
     /// implementation like `Copy` or `Sized`.
-    BuiltinDerivedObligation(DerivedObligationCause<'tcx>),
+    BuiltinDerived(DerivedCause<'tcx>),
 
     /// Derived obligation (i.e. `where` clause) on an user-provided impl
     /// or a trait alias.
-    ImplDerivedObligation(Box<ImplDerivedObligationCause<'tcx>>),
+    ImplDerived(Box<ImplDerivedCause<'tcx>>),
 
     /// Derived obligation for WF goals.
-    WellFormedDerivedObligation(DerivedObligationCause<'tcx>),
+    WellFormedDerived(DerivedCause<'tcx>),
 
-    FunctionArgumentObligation {
+    /// Derived obligation refined to point at a specific argument in
+    /// a call or method expression.
+    FunctionArg {
         /// The node of the relevant argument in the function call.
         arg_hir_id: HirId,
         /// The node of the function call.
@@ -353,7 +342,7 @@
 
     /// Error derived when checking an impl item is compatible with
     /// its corresponding trait item's definition
-    CompareImplItemObligation {
+    CompareImplItem {
         impl_item_def_id: LocalDefId,
         trait_item_def_id: DefId,
         kind: ty::AssocKind,
@@ -432,8 +421,8 @@
     /// then it will be used to perform HIR-based wf checking
     /// after an error occurs, in order to generate a more precise error span.
     /// This is purely for diagnostic purposes - it is always
-    /// correct to use `MiscObligation` instead, or to specify
-    /// `WellFormed(None)`
+    /// correct to use `Misc` instead, or to specify
+    /// `WellFormed(None)`.
     WellFormed(Option<WellFormedLoc>),
 
     /// From `match_impl`. The cause for us having to match an impl, and the DefId we are matching against.
@@ -501,8 +490,8 @@
 
 #[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
 #[derive(TypeVisitable, TypeFoldable)]
-pub struct ImplDerivedObligationCause<'tcx> {
-    pub derived: DerivedObligationCause<'tcx>,
+pub struct ImplDerivedCause<'tcx> {
+    pub derived: DerivedCause<'tcx>,
     /// The `DefId` of the `impl` that gave rise to the `derived` obligation.
     /// If the `derived` obligation arose from a trait alias, which conceptually has a synthetic impl,
     /// then this will be the `DefId` of that trait alias. Care should therefore be taken to handle
@@ -540,10 +529,10 @@
 
     pub fn parent(&self) -> Option<(&Self, Option<ty::PolyTraitPredicate<'tcx>>)> {
         match self {
-            FunctionArgumentObligation { parent_code, .. } => Some((parent_code, None)),
-            BuiltinDerivedObligation(derived)
-            | WellFormedDerivedObligation(derived)
-            | ImplDerivedObligation(box ImplDerivedObligationCause { derived, .. }) => {
+            ObligationCauseCode::FunctionArg { parent_code, .. } => Some((parent_code, None)),
+            ObligationCauseCode::BuiltinDerived(derived)
+            | ObligationCauseCode::WellFormedDerived(derived)
+            | ObligationCauseCode::ImplDerived(box ImplDerivedCause { derived, .. }) => {
                 Some((&derived.parent_code, Some(derived.parent_trait_pred)))
             }
             _ => None,
@@ -552,7 +541,7 @@
 
     pub fn peel_match_impls(&self) -> &Self {
         match self {
-            MatchImpl(cause, _) => cause.code(),
+            ObligationCauseCode::MatchImpl(cause, _) => cause.code(),
             _ => self,
         }
     }
@@ -598,7 +587,7 @@
 
 #[derive(Clone, Debug, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
 #[derive(TypeVisitable, TypeFoldable)]
-pub struct DerivedObligationCause<'tcx> {
+pub struct DerivedCause<'tcx> {
     /// The trait predicate of the parent obligation that led to the
     /// current obligation. Note that only trait obligations lead to
     /// derived obligations, so we just store the trait predicate here
@@ -748,32 +737,6 @@
     pub nested: Vec<N>,
 }
 
-#[derive(Copy, Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Debug)]
-pub enum BuiltinImplSource {
-    /// Some builtin impl we don't need to differentiate. This should be used
-    /// unless more specific information is necessary.
-    Misc,
-    /// A builtin impl for trait objects.
-    ///
-    /// The vtable is formed by concatenating together the method lists of
-    /// the base object trait and all supertraits, pointers to supertrait vtable will
-    /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods
-    /// in that vtable.
-    Object { vtable_base: usize },
-    /// The vtable is formed by concatenating together the method lists of
-    /// the base object trait and all supertraits, pointers to supertrait vtable will
-    /// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable
-    /// within that vtable.
-    TraitUpcasting { vtable_vptr_slot: Option<usize> },
-    /// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`.
-    ///
-    /// This needs to be a separate variant as it is still unstable and we need to emit
-    /// a feature error when using it on stable.
-    TupleUnsizing,
-}
-
-TrivialTypeTraversalImpls! { BuiltinImplSource }
-
 #[derive(Clone, Debug, PartialEq, Eq, Hash, HashStable, PartialOrd, Ord)]
 pub enum ObjectSafetyViolation {
     /// `Self: Sized` declared on the trait.
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index 70f3532..66e5030 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -12,6 +12,8 @@
 use crate::ty::{self, Ty, TyCtxt};
 use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
 use rustc_span::Span;
+// FIXME: Remove this import and import via `traits::solve`.
+pub use rustc_next_trait_solver::solve::NoSolution;
 
 pub mod type_op {
     use crate::ty::fold::TypeFoldable;
@@ -89,9 +91,6 @@
 pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
     Canonical<'tcx, ty::ParamEnvAnd<'tcx, type_op::Normalize<T>>>;
 
-#[derive(Copy, Clone, Debug, Hash, HashStable, PartialEq, Eq)]
-pub struct NoSolution;
-
 impl<'tcx> From<TypeError<'tcx>> for NoSolution {
     fn from(_: TypeError<'tcx>) -> NoSolution {
         NoSolution
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index 3ad6b68..c8c16ec 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -1,122 +1,24 @@
 use rustc_ast_ir::try_visit;
 use rustc_data_structures::intern::Interned;
 use rustc_macros::{HashStable, TypeFoldable, TypeVisitable};
-use rustc_span::def_id::DefId;
+use rustc_next_trait_solver as ir;
+pub use rustc_next_trait_solver::solve::*;
 
-use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints};
-use crate::traits::query::NoSolution;
-use crate::traits::Canonical;
+use crate::infer::canonical::QueryRegionConstraints;
 use crate::ty::{
-    self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable,
-    TypeVisitor,
+    self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor,
 };
 
-use super::BuiltinImplSource;
-
 mod cache;
-pub mod inspect;
 
 pub use cache::{CacheData, EvaluationCache};
 
-/// A goal is a statement, i.e. `predicate`, we want to prove
-/// given some assumptions, i.e. `param_env`.
-///
-/// Most of the time the `param_env` contains the `where`-bounds of the function
-/// we're currently typechecking while the `predicate` is some trait bound.
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub struct Goal<'tcx, P> {
-    pub predicate: P,
-    pub param_env: ty::ParamEnv<'tcx>,
-}
-
-impl<'tcx, P> Goal<'tcx, P> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        param_env: ty::ParamEnv<'tcx>,
-        predicate: impl ToPredicate<'tcx, P>,
-    ) -> Goal<'tcx, P> {
-        Goal { param_env, predicate: predicate.to_predicate(tcx) }
-    }
-
-    /// Updates the goal to one with a different `predicate` but the same `param_env`.
-    pub fn with<Q>(self, tcx: TyCtxt<'tcx>, predicate: impl ToPredicate<'tcx, Q>) -> Goal<'tcx, Q> {
-        Goal { param_env: self.param_env, predicate: predicate.to_predicate(tcx) }
-    }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub struct Response<'tcx> {
-    pub certainty: Certainty,
-    pub var_values: CanonicalVarValues<'tcx>,
-    /// Additional constraints returned by this query.
-    pub external_constraints: ExternalConstraints<'tcx>,
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub enum Certainty {
-    Yes,
-    Maybe(MaybeCause),
-}
-
-impl Certainty {
-    pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
-
-    /// Use this function to merge the certainty of multiple nested subgoals.
-    ///
-    /// Given an impl like `impl<T: Foo + Bar> Baz for T {}`, we have 2 nested
-    /// subgoals whenever we use the impl as a candidate: `T: Foo` and `T: Bar`.
-    /// If evaluating `T: Foo` results in ambiguity and `T: Bar` results in
-    /// success, we merge these two responses. This results in ambiguity.
-    ///
-    /// If we unify ambiguity with overflow, we return overflow. This doesn't matter
-    /// inside of the solver as we do not distinguish ambiguity from overflow. It does
-    /// however matter for diagnostics. If `T: Foo` resulted in overflow and `T: Bar`
-    /// in ambiguity without changing the inference state, we still want to tell the
-    /// user that `T: Baz` results in overflow.
-    pub fn unify_with(self, other: Certainty) -> Certainty {
-        match (self, other) {
-            (Certainty::Yes, Certainty::Yes) => Certainty::Yes,
-            (Certainty::Yes, Certainty::Maybe(_)) => other,
-            (Certainty::Maybe(_), Certainty::Yes) => self,
-            (Certainty::Maybe(a), Certainty::Maybe(b)) => Certainty::Maybe(a.unify_with(b)),
-        }
-    }
-
-    pub const fn overflow(suggest_increasing_limit: bool) -> Certainty {
-        Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit })
-    }
-}
-
-/// Why we failed to evaluate a goal.
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub enum MaybeCause {
-    /// We failed due to ambiguity. This ambiguity can either
-    /// be a true ambiguity, i.e. there are multiple different answers,
-    /// or we hit a case where we just don't bother, e.g. `?x: Trait` goals.
-    Ambiguity,
-    /// We gave up due to an overflow, most often by hitting the recursion limit.
-    Overflow { suggest_increasing_limit: bool },
-}
-
-impl MaybeCause {
-    fn unify_with(self, other: MaybeCause) -> MaybeCause {
-        match (self, other) {
-            (MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity,
-            (MaybeCause::Ambiguity, MaybeCause::Overflow { .. }) => other,
-            (MaybeCause::Overflow { .. }, MaybeCause::Ambiguity) => self,
-            (
-                MaybeCause::Overflow { suggest_increasing_limit: a },
-                MaybeCause::Overflow { suggest_increasing_limit: b },
-            ) => MaybeCause::Overflow { suggest_increasing_limit: a || b },
-        }
-    }
-}
-
-#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub struct QueryInput<'tcx, T> {
-    pub goal: Goal<'tcx, T>,
-    pub predefined_opaques_in_body: PredefinedOpaques<'tcx>,
-}
+pub type Goal<'tcx, P> = ir::solve::Goal<TyCtxt<'tcx>, P>;
+pub type QueryInput<'tcx, P> = ir::solve::QueryInput<TyCtxt<'tcx>, P>;
+pub type QueryResult<'tcx> = ir::solve::QueryResult<TyCtxt<'tcx>>;
+pub type CandidateSource<'tcx> = ir::solve::CandidateSource<TyCtxt<'tcx>>;
+pub type CanonicalInput<'tcx, P = ty::Predicate<'tcx>> = ir::solve::CanonicalInput<TyCtxt<'tcx>, P>;
+pub type CanonicalResponse<'tcx> = ir::solve::CanonicalResponse<TyCtxt<'tcx>>;
 
 /// Additional constraints returned on success.
 #[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default)]
@@ -135,18 +37,6 @@
     }
 }
 
-pub type CanonicalInput<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, QueryInput<'tcx, T>>;
-
-pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>;
-
-/// The result of evaluating a canonical query.
-///
-/// FIXME: We use a different type than the existing canonical queries. This is because
-/// we need to add a `Certainty` for `overflow` and may want to restructure this code without
-/// having to worry about changes to currently used code. Once we've made progress on this
-/// solver, merge the two responses again.
-pub type QueryResult<'tcx> = Result<CanonicalResponse<'tcx>, NoSolution>;
-
 #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)]
 pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>);
 
@@ -253,91 +143,3 @@
         self.opaque_types.visit_with(visitor)
     }
 }
-
-/// Why a specific goal has to be proven.
-///
-/// This is necessary as we treat nested goals different depending on
-/// their source.
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TypeVisitable, TypeFoldable)]
-pub enum GoalSource {
-    Misc,
-    /// We're proving a where-bound of an impl.
-    ///
-    /// FIXME(-Znext-solver=coinductive): Explain how and why this
-    /// changes whether cycles are coinductive.
-    ///
-    /// This also impacts whether we erase constraints on overflow.
-    /// Erasing constraints is generally very useful for perf and also
-    /// results in better error messages by avoiding spurious errors.
-    /// We do not erase overflow constraints in `normalizes-to` goals unless
-    /// they are from an impl where-clause. This is necessary due to
-    /// backwards compatability, cc trait-system-refactor-initiatitive#70.
-    ImplWhereBound,
-    /// Instantiating a higher-ranked goal and re-proving it.
-    InstantiateHigherRanked,
-}
-
-/// Possible ways the given goal can be proven.
-#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-pub enum CandidateSource {
-    /// A user written impl.
-    ///
-    /// ## Examples
-    ///
-    /// ```rust
-    /// fn main() {
-    ///     let x: Vec<u32> = Vec::new();
-    ///     // This uses the impl from the standard library to prove `Vec<T>: Clone`.
-    ///     let y = x.clone();
-    /// }
-    /// ```
-    Impl(DefId),
-    /// A builtin impl generated by the compiler. When adding a new special
-    /// trait, try to use actual impls whenever possible. Builtin impls should
-    /// only be used in cases where the impl cannot be manually be written.
-    ///
-    /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
-    /// For a list of all traits with builtin impls, check out the
-    /// `EvalCtxt::assemble_builtin_impl_candidates` method.
-    BuiltinImpl(BuiltinImplSource),
-    /// An assumption from the environment.
-    ///
-    /// More precisely we've used the `n-th` assumption in the `param_env`.
-    ///
-    /// ## Examples
-    ///
-    /// ```rust
-    /// fn is_clone<T: Clone>(x: T) -> (T, T) {
-    ///     // This uses the assumption `T: Clone` from the `where`-bounds
-    ///     // to prove `T: Clone`.
-    ///     (x.clone(), x)
-    /// }
-    /// ```
-    ParamEnv(usize),
-    /// If the self type is an alias type, e.g. an opaque type or a projection,
-    /// we know the bounds on that alias to hold even without knowing its concrete
-    /// underlying type.
-    ///
-    /// More precisely this candidate is using the `n-th` bound in the `item_bounds` of
-    /// the self type.
-    ///
-    /// ## Examples
-    ///
-    /// ```rust
-    /// trait Trait {
-    ///     type Assoc: Clone;
-    /// }
-    ///
-    /// fn foo<T: Trait>(x: <T as Trait>::Assoc) {
-    ///     // We prove `<T as Trait>::Assoc` by looking at the bounds on `Assoc` in
-    ///     // in the trait definition.
-    ///     let _y = x.clone();
-    /// }
-    /// ```
-    AliasBound,
-    /// A candidate that is registered only during coherence to represent some
-    /// yet-unknown impl that could be produced downstream without violating orphan
-    /// rules.
-    // FIXME: Merge this with the forced ambiguity candidates, so those don't use `Misc`.
-    CoherenceUnknowable,
-}
diff --git a/compiler/rustc_middle/src/traits/solve/cache.rs b/compiler/rustc_middle/src/traits/solve/cache.rs
index 4f90af0..2ff4ade 100644
--- a/compiler/rustc_middle/src/traits/solve/cache.rs
+++ b/compiler/rustc_middle/src/traits/solve/cache.rs
@@ -14,11 +14,11 @@
     map: Lock<FxHashMap<CanonicalInput<'tcx>, CacheEntry<'tcx>>>,
 }
 
-#[derive(PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq)]
 pub struct CacheData<'tcx> {
     pub result: QueryResult<'tcx>,
-    pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>,
-    pub reached_depth: usize,
+    pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]>,
+    pub additional_depth: usize,
     pub encountered_overflow: bool,
 }
 
@@ -28,8 +28,8 @@
         &self,
         tcx: TyCtxt<'tcx>,
         key: CanonicalInput<'tcx>,
-        proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>,
-        reached_depth: usize,
+        proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]>,
+        additional_depth: usize,
         encountered_overflow: bool,
         cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
         dep_node: DepNodeIndex,
@@ -40,17 +40,17 @@
         let data = WithDepNode::new(dep_node, QueryData { result, proof_tree });
         entry.cycle_participants.extend(cycle_participants);
         if encountered_overflow {
-            entry.with_overflow.insert(reached_depth, data);
+            entry.with_overflow.insert(additional_depth, data);
         } else {
-            entry.success = Some(Success { data, reached_depth });
+            entry.success = Some(Success { data, additional_depth });
         }
 
         if cfg!(debug_assertions) {
             drop(map);
-            if Some(CacheData { result, proof_tree, reached_depth, encountered_overflow })
-                != self.get(tcx, key, |_| false, Limit(reached_depth))
-            {
-                bug!("unable to retrieve inserted element from cache: {key:?}");
+            let expected = CacheData { result, proof_tree, additional_depth, encountered_overflow };
+            let actual = self.get(tcx, key, [], Limit(additional_depth));
+            if !actual.as_ref().is_some_and(|actual| expected == *actual) {
+                bug!("failed to lookup inserted element for {key:?}: {expected:?} != {actual:?}");
             }
         }
     }
@@ -63,23 +63,25 @@
         &self,
         tcx: TyCtxt<'tcx>,
         key: CanonicalInput<'tcx>,
-        cycle_participant_in_stack: impl FnOnce(&FxHashSet<CanonicalInput<'tcx>>) -> bool,
+        stack_entries: impl IntoIterator<Item = CanonicalInput<'tcx>>,
         available_depth: Limit,
     ) -> Option<CacheData<'tcx>> {
         let map = self.map.borrow();
         let entry = map.get(&key)?;
 
-        if cycle_participant_in_stack(&entry.cycle_participants) {
-            return None;
+        for stack_entry in stack_entries {
+            if entry.cycle_participants.contains(&stack_entry) {
+                return None;
+            }
         }
 
         if let Some(ref success) = entry.success {
-            if available_depth.value_within_limit(success.reached_depth) {
+            if available_depth.value_within_limit(success.additional_depth) {
                 let QueryData { result, proof_tree } = success.data.get(tcx);
                 return Some(CacheData {
                     result,
                     proof_tree,
-                    reached_depth: success.reached_depth,
+                    additional_depth: success.additional_depth,
                     encountered_overflow: false,
                 });
             }
@@ -90,7 +92,7 @@
             CacheData {
                 result,
                 proof_tree,
-                reached_depth: available_depth.0,
+                additional_depth: available_depth.0,
                 encountered_overflow: true,
             }
         })
@@ -99,13 +101,13 @@
 
 struct Success<'tcx> {
     data: WithDepNode<QueryData<'tcx>>,
-    reached_depth: usize,
+    additional_depth: usize,
 }
 
 #[derive(Clone, Copy)]
 pub struct QueryData<'tcx> {
     pub result: QueryResult<'tcx>,
-    pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]>,
+    pub proof_tree: Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]>,
 }
 
 /// The cache entry for a goal `CanonicalInput`.
diff --git a/compiler/rustc_middle/src/traits/solve/inspect.rs b/compiler/rustc_middle/src/traits/solve/inspect.rs
deleted file mode 100644
index 2ddcb8a..0000000
--- a/compiler/rustc_middle/src/traits/solve/inspect.rs
+++ /dev/null
@@ -1,158 +0,0 @@
-//! Data structure used to inspect trait solver behavior.
-//!
-//! During trait solving we optionally build "proof trees", the root of
-//! which is a [GoalEvaluation] with [GoalEvaluationKind::Root]. These
-//! trees are used to improve the debug experience and are also used by
-//! the compiler itself to provide necessary context for error messages.
-//!
-//! Because each nested goal in the solver gets [canonicalized] separately
-//! and we discard inference progress via "probes", we cannot mechanically
-//! use proof trees without somehow "lifting up" data local to the current
-//! `InferCtxt`. Any data used mechanically is therefore canonicalized and
-//! stored as [CanonicalState]. As printing canonicalized data worsens the
-//! debugging dumps, we do not simply canonicalize everything.
-//!
-//! This means proof trees contain inference variables and placeholders
-//! local to a different `InferCtxt` which must not be used with the
-//! current one.
-//!
-//! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
-
-use super::{
-    CandidateSource, Canonical, CanonicalInput, Certainty, Goal, GoalSource, NoSolution,
-    QueryInput, QueryResult,
-};
-use crate::{infer::canonical::CanonicalVarValues, ty};
-use format::ProofTreeFormatter;
-use rustc_macros::{TypeFoldable, TypeVisitable};
-use std::fmt::{Debug, Write};
-
-mod format;
-
-/// Some `data` together with information about how they relate to the input
-/// of the canonical query.
-///
-/// This is only ever used as [CanonicalState]. Any type information in proof
-/// trees used mechanically has to be canonicalized as we otherwise leak
-/// inference variables from a nested `InferCtxt`.
-#[derive(Debug, Clone, Copy, Eq, PartialEq, TypeFoldable, TypeVisitable)]
-pub struct State<'tcx, T> {
-    pub var_values: CanonicalVarValues<'tcx>,
-    pub data: T,
-}
-
-pub type CanonicalState<'tcx, T> = Canonical<'tcx, State<'tcx, T>>;
-
-/// When evaluating the root goals we also store the
-/// original values for the `CanonicalVarValues` of the
-/// canonicalized goal. We use this to map any [CanonicalState]
-/// from the local `InferCtxt` of the solver query to
-/// the `InferCtxt` of the caller.
-#[derive(Eq, PartialEq)]
-pub enum GoalEvaluationKind<'tcx> {
-    Root { orig_values: Vec<ty::GenericArg<'tcx>> },
-    Nested,
-}
-
-#[derive(Eq, PartialEq)]
-pub struct GoalEvaluation<'tcx> {
-    pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    pub kind: GoalEvaluationKind<'tcx>,
-    pub evaluation: CanonicalGoalEvaluation<'tcx>,
-}
-
-#[derive(Eq, PartialEq, Debug)]
-pub struct CanonicalGoalEvaluation<'tcx> {
-    pub goal: CanonicalInput<'tcx>,
-    pub kind: CanonicalGoalEvaluationKind<'tcx>,
-    pub result: QueryResult<'tcx>,
-}
-
-#[derive(Eq, PartialEq, Debug)]
-pub enum CanonicalGoalEvaluationKind<'tcx> {
-    Overflow,
-    CycleInStack,
-    ProvisionalCacheHit,
-    Evaluation { revisions: &'tcx [GoalEvaluationStep<'tcx>] },
-}
-impl Debug for GoalEvaluation<'_> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        ProofTreeFormatter::new(f).format_goal_evaluation(self)
-    }
-}
-
-#[derive(Eq, PartialEq)]
-pub struct AddedGoalsEvaluation<'tcx> {
-    pub evaluations: Vec<Vec<GoalEvaluation<'tcx>>>,
-    pub result: Result<Certainty, NoSolution>,
-}
-
-#[derive(Eq, PartialEq, Debug)]
-pub struct GoalEvaluationStep<'tcx> {
-    pub instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
-
-    /// The actual evaluation of the goal, always `ProbeKind::Root`.
-    pub evaluation: Probe<'tcx>,
-}
-
-/// A self-contained computation during trait solving. This either
-/// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation
-/// of a goal.
-#[derive(Eq, PartialEq)]
-pub struct Probe<'tcx> {
-    /// What happened inside of this probe in chronological order.
-    pub steps: Vec<ProbeStep<'tcx>>,
-    pub kind: ProbeKind<'tcx>,
-    pub final_state: CanonicalState<'tcx, ()>,
-}
-
-impl Debug for Probe<'_> {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        ProofTreeFormatter::new(f).format_probe(self)
-    }
-}
-
-#[derive(Eq, PartialEq)]
-pub enum ProbeStep<'tcx> {
-    /// We added a goal to the `EvalCtxt` which will get proven
-    /// the next time `EvalCtxt::try_evaluate_added_goals` is called.
-    AddGoal(GoalSource, CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
-    /// The inside of a `EvalCtxt::try_evaluate_added_goals` call.
-    EvaluateGoals(AddedGoalsEvaluation<'tcx>),
-    /// A call to `probe` while proving the current goal. This is
-    /// used whenever there are multiple candidates to prove the
-    /// current goalby .
-    NestedProbe(Probe<'tcx>),
-    /// A trait goal was satisfied by an impl candidate.
-    RecordImplArgs { impl_args: CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> },
-    /// A call to `EvalCtxt::evaluate_added_goals_make_canonical_response` with
-    /// `Certainty` was made. This is the certainty passed in, so it's not unified
-    /// with the certainty of the `try_evaluate_added_goals` that is done within;
-    /// if it's `Certainty::Yes`, then we can trust that the candidate is "finished"
-    /// and we didn't force ambiguity for some reason.
-    MakeCanonicalResponse { shallow_certainty: Certainty },
-}
-
-/// What kind of probe we're in. In case the probe represents a candidate, or
-/// the final result of the current goal - via [ProbeKind::Root] - we also
-/// store the [QueryResult].
-#[derive(Debug, PartialEq, Eq, Clone, Copy)]
-pub enum ProbeKind<'tcx> {
-    /// The root inference context while proving a goal.
-    Root { result: QueryResult<'tcx> },
-    /// Trying to normalize an alias by at least one step in `NormalizesTo`.
-    TryNormalizeNonRigid { result: QueryResult<'tcx> },
-    /// Probe entered when normalizing the self ty during candidate assembly
-    NormalizedSelfTyAssembly,
-    /// A candidate for proving a trait or alias-relate goal.
-    TraitCandidate { source: CandidateSource, result: QueryResult<'tcx> },
-    /// Used in the probe that wraps normalizing the non-self type for the unsize
-    /// trait, which is also structurally matched on.
-    UnsizeAssembly,
-    /// During upcasting from some source object to target object type, used to
-    /// do a probe to find out what projection type(s) may be used to prove that
-    /// the source type upholds all of the target type's object bounds.
-    UpcastProjectionCompatibility,
-    /// Try to unify an opaque type with an existing key in the storage.
-    OpaqueTypeStorageLookup { result: QueryResult<'tcx> },
-}
diff --git a/compiler/rustc_middle/src/traits/util.rs b/compiler/rustc_middle/src/traits/util.rs
index 3419827..707e076 100644
--- a/compiler/rustc_middle/src/traits/util.rs
+++ b/compiler/rustc_middle/src/traits/util.rs
@@ -1,6 +1,6 @@
 use rustc_data_structures::fx::FxHashSet;
 
-use crate::ty::{Clause, PolyTraitRef, ToPolyTraitRef, ToPredicate, TyCtxt};
+use crate::ty::{Clause, PolyTraitRef, ToPolyTraitRef, TyCtxt, Upcast};
 
 /// Given a [`PolyTraitRef`], get the [`Clause`]s implied by the trait's definition.
 ///
@@ -11,7 +11,7 @@
     tcx: TyCtxt<'tcx>,
     trait_ref: PolyTraitRef<'tcx>,
 ) -> impl Iterator<Item = Clause<'tcx>> {
-    let clause = trait_ref.to_predicate(tcx);
+    let clause = trait_ref.upcast(tcx);
     Elaborator { tcx, visited: FxHashSet::from_iter([clause]), stack: vec![clause] }
 }
 
diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs
index 9badf65..6d7b625 100644
--- a/compiler/rustc_middle/src/ty/adjustment.rs
+++ b/compiler/rustc_middle/src/ty/adjustment.rs
@@ -15,7 +15,7 @@
 
     /// Go from a non-capturing closure to an fn pointer or an unsafe fn pointer.
     /// It cannot convert a closure that requires unsafe.
-    ClosureFnPointer(hir::Unsafety),
+    ClosureFnPointer(hir::Safety),
 
     /// Go from a mut raw pointer to a const raw pointer.
     MutToConstPointer,
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index c0effe9..07652b4 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -115,18 +115,11 @@
     }
 }
 
-impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E>
-    for ty::Binder<'tcx, ty::PredicateKind<'tcx>>
-{
-    fn encode(&self, e: &mut E) {
-        self.bound_vars().encode(e);
-        encode_with_shorthand(e, &self.skip_binder(), TyEncoder::predicate_shorthands);
-    }
-}
-
 impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Predicate<'tcx> {
     fn encode(&self, e: &mut E) {
-        self.kind().encode(e);
+        let kind = self.kind();
+        kind.bound_vars().encode(e);
+        encode_with_shorthand(e, &kind.skip_binder(), TyEncoder::predicate_shorthands);
     }
 }
 
@@ -233,13 +226,11 @@
     }
 }
 
-impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D>
-    for ty::Binder<'tcx, ty::PredicateKind<'tcx>>
-{
-    fn decode(decoder: &mut D) -> ty::Binder<'tcx, ty::PredicateKind<'tcx>> {
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Predicate<'tcx> {
+    fn decode(decoder: &mut D) -> ty::Predicate<'tcx> {
         let bound_vars = Decodable::decode(decoder);
         // Handle shorthands first, if we have a usize > 0x80.
-        ty::Binder::bind_with_vars(
+        let predicate_kind = ty::Binder::bind_with_vars(
             if decoder.positioned_at_shorthand() {
                 let pos = decoder.read_usize();
                 assert!(pos >= SHORTHAND_OFFSET);
@@ -250,13 +241,7 @@
                 <ty::PredicateKind<'tcx> as Decodable<D>>::decode(decoder)
             },
             bound_vars,
-        )
-    }
-}
-
-impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Predicate<'tcx> {
-    fn decode(decoder: &mut D) -> ty::Predicate<'tcx> {
-        let predicate_kind = Decodable::decode(decoder);
+        );
         decoder.interner().mk_predicate(predicate_kind)
     }
 }
@@ -599,32 +584,3 @@
         }
     }
 }
-
-macro_rules! impl_binder_encode_decode {
-    ($($t:ty),+ $(,)?) => {
-        $(
-            impl<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>> Encodable<E> for ty::Binder<'tcx, $t> {
-                fn encode(&self, e: &mut E) {
-                    self.bound_vars().encode(e);
-                    self.as_ref().skip_binder().encode(e);
-                }
-            }
-            impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> Decodable<D> for ty::Binder<'tcx, $t> {
-                fn decode(decoder: &mut D) -> Self {
-                    let bound_vars = Decodable::decode(decoder);
-                    ty::Binder::bind_with_vars(Decodable::decode(decoder), bound_vars)
-                }
-            }
-        )*
-    }
-}
-
-impl_binder_encode_decode! {
-    &'tcx ty::List<Ty<'tcx>>,
-    ty::FnSig<'tcx>,
-    ty::Predicate<'tcx>,
-    ty::TraitPredicate<'tcx>,
-    ty::ExistentialPredicate<'tcx>,
-    ty::TraitRef<'tcx>,
-    ty::ExistentialTraitRef<'tcx>,
-}
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index a65b3a4..f7cc055 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -7,8 +7,7 @@
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::LocalDefId;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
-use rustc_type_ir::ConstKind as IrConstKind;
-use rustc_type_ir::{ConstTy, IntoKind, TypeFlags, WithCachedTypeInfo};
+use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo};
 
 mod int;
 mod kind;
@@ -20,7 +19,8 @@
 use rustc_span::DUMMY_SP;
 pub use valtree::*;
 
-pub type ConstKind<'tcx> = IrConstKind<TyCtxt<'tcx>>;
+pub type ConstKind<'tcx> = ir::ConstKind<TyCtxt<'tcx>>;
+pub type UnevaluatedConst<'tcx> = ir::UnevaluatedConst<TyCtxt<'tcx>>;
 
 #[cfg(target_pointer_width = "64")]
 rustc_data_structures::static_assert_size!(ConstKind<'_>, 32);
@@ -30,7 +30,7 @@
 #[rustc_pass_by_value]
 pub struct Const<'tcx>(pub(super) Interned<'tcx, WithCachedTypeInfo<ConstData<'tcx>>>);
 
-impl<'tcx> IntoKind for Const<'tcx> {
+impl<'tcx> rustc_type_ir::inherent::IntoKind for Const<'tcx> {
     type Kind = ConstKind<'tcx>;
 
     fn kind(self) -> ConstKind<'tcx> {
@@ -48,12 +48,6 @@
     }
 }
 
-impl<'tcx> ConstTy<TyCtxt<'tcx>> for Const<'tcx> {
-    fn ty(self) -> Ty<'tcx> {
-        self.ty()
-    }
-}
-
 /// Typed constant value.
 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
 #[derive(HashStable, TyEncodable, TyDecodable)]
@@ -180,7 +174,15 @@
     }
 }
 
-impl<'tcx> rustc_type_ir::new::Const<TyCtxt<'tcx>> for Const<'tcx> {
+impl<'tcx> rustc_type_ir::inherent::Const<TyCtxt<'tcx>> for Const<'tcx> {
+    fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferConst, ty: Ty<'tcx>) -> Self {
+        Const::new_infer(tcx, infer, ty)
+    }
+
+    fn new_var(tcx: TyCtxt<'tcx>, vid: ty::ConstVid, ty: Ty<'tcx>) -> Self {
+        Const::new_var(tcx, vid, ty)
+    }
+
     fn new_anon_bound(
         tcx: TyCtxt<'tcx>,
         debruijn: ty::DebruijnIndex,
@@ -189,6 +191,18 @@
     ) -> Self {
         Const::new_bound(tcx, debruijn, var, ty)
     }
+
+    fn new_unevaluated(
+        interner: TyCtxt<'tcx>,
+        uv: ty::UnevaluatedConst<'tcx>,
+        ty: Ty<'tcx>,
+    ) -> Self {
+        Const::new_unevaluated(interner, uv, ty)
+    }
+
+    fn ty(self) -> Ty<'tcx> {
+        self.ty()
+    }
 }
 
 impl<'tcx> Const<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 7e49b0a..d7ae050 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -1,30 +1,15 @@
 use super::Const;
 use crate::mir;
 use crate::ty::abstract_const::CastKind;
-use crate::ty::GenericArgsRef;
 use crate::ty::{self, visit::TypeVisitableExt as _, List, Ty, TyCtxt};
-use rustc_hir::def_id::DefId;
-use rustc_macros::{HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
+use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
 
-/// An unevaluated (potentially generic) constant used in the type-system.
-#[derive(Copy, Clone, Eq, PartialEq, TyEncodable, TyDecodable)]
-#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
-pub struct UnevaluatedConst<'tcx> {
-    pub def: DefId,
-    pub args: GenericArgsRef<'tcx>,
-}
-
-impl rustc_errors::IntoDiagArg for UnevaluatedConst<'_> {
-    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
-        format!("{self:?}").into_diag_arg()
-    }
-}
-
-impl<'tcx> UnevaluatedConst<'tcx> {
+#[extension(pub(crate) trait UnevaluatedConstEvalExt<'tcx>)]
+impl<'tcx> ty::UnevaluatedConst<'tcx> {
     /// FIXME(RalfJung): I cannot explain what this does or why it makes sense, but not doing this
     /// hurts performance.
     #[inline]
-    pub(crate) fn prepare_for_eval(
+    fn prepare_for_eval(
         self,
         tcx: TyCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
@@ -55,13 +40,6 @@
     }
 }
 
-impl<'tcx> UnevaluatedConst<'tcx> {
-    #[inline]
-    pub fn new(def: DefId, args: GenericArgsRef<'tcx>) -> UnevaluatedConst<'tcx> {
-        UnevaluatedConst { def, args }
-    }
-}
-
 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
 #[derive(HashStable, TyEncodable, TyDecodable, TypeVisitable, TypeFoldable)]
 pub enum Expr<'tcx> {
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index d2eacdf..896114e 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -4,6 +4,8 @@
 
 pub mod tls;
 
+pub use rustc_type_ir::lift::Lift;
+
 use crate::arena::Arena;
 use crate::dep_graph::{DepGraph, DepKindStruct};
 use crate::infer::canonical::{CanonicalParamEnvCache, CanonicalVarInfo, CanonicalVarInfos};
@@ -24,12 +26,12 @@
 use crate::traits::solve::{
     ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData,
 };
+use crate::ty::predicate::ExistentialPredicateStableCmpExt as _;
 use crate::ty::{
     self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, ConstData,
     GenericParamDefKind, ImplPolarity, List, ListWithCachedTypeInfo, ParamConst, ParamTy, Pattern,
     PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity,
-    Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, TypeVisitable,
-    Visibility,
+    Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, Visibility,
 };
 use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
 use rustc_ast::{self as ast, attr};
@@ -73,6 +75,7 @@
 use rustc_type_ir::WithCachedTypeInfo;
 use rustc_type_ir::{CollectAndApply, Interner, TypeFlags};
 
+use std::assert_matches::assert_matches;
 use std::borrow::Borrow;
 use std::cmp::Ordering;
 use std::fmt;
@@ -85,21 +88,25 @@
 #[allow(rustc::usage_of_ty_tykind)]
 impl<'tcx> Interner for TyCtxt<'tcx> {
     type DefId = DefId;
-    type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
     type AdtDef = ty::AdtDef<'tcx>;
+
     type GenericArgs = ty::GenericArgsRef<'tcx>;
+    type OwnItemArgs = &'tcx [ty::GenericArg<'tcx>];
     type GenericArg = ty::GenericArg<'tcx>;
     type Term = ty::Term<'tcx>;
 
-    type Binder<T: TypeVisitable<TyCtxt<'tcx>>> = Binder<'tcx, T>;
-    type BoundVars = &'tcx List<ty::BoundVariableKind>;
-    type BoundVar = ty::BoundVariableKind;
+    type BoundVarKinds = &'tcx List<ty::BoundVariableKind>;
+    type BoundVarKind = ty::BoundVariableKind;
+
     type CanonicalVars = CanonicalVarInfos<'tcx>;
+    type PredefinedOpaques = solve::PredefinedOpaques<'tcx>;
+    type DefiningOpaqueTypes = &'tcx ty::List<LocalDefId>;
+    type ExternalConstraints = ExternalConstraints<'tcx>;
+    type GoalEvaluationSteps = &'tcx [solve::inspect::GoalEvaluationStep<TyCtxt<'tcx>>];
 
     type Ty = Ty<'tcx>;
-    type Pat = Pattern<'tcx>;
     type Tys = &'tcx List<Ty<'tcx>>;
-    type AliasTy = ty::AliasTy<'tcx>;
+    type FnInputTys = &'tcx [Ty<'tcx>];
     type ParamTy = ParamTy;
     type BoundTy = ty::BoundTy;
     type PlaceholderTy = ty::PlaceholderType;
@@ -109,8 +116,11 @@
     type PolyFnSig = PolyFnSig<'tcx>;
     type AllocId = crate::mir::interpret::AllocId;
 
+    type Pat = Pattern<'tcx>;
+    type Safety = hir::Safety;
+    type Abi = abi::Abi;
+
     type Const = ty::Const<'tcx>;
-    type AliasConst = ty::UnevaluatedConst<'tcx>;
     type PlaceholderConst = ty::PlaceholderConst;
     type ParamConst = ty::ParamConst;
     type BoundConst = ty::BoundVar;
@@ -119,25 +129,118 @@
 
     type Region = Region<'tcx>;
     type EarlyParamRegion = ty::EarlyParamRegion;
-    type BoundRegion = ty::BoundRegion;
     type LateParamRegion = ty::LateParamRegion;
-    type InferRegion = ty::RegionVid;
+    type BoundRegion = ty::BoundRegion;
     type PlaceholderRegion = ty::PlaceholderRegion;
 
+    type ParamEnv = ty::ParamEnv<'tcx>;
     type Predicate = Predicate<'tcx>;
-    type TraitPredicate = ty::TraitPredicate<'tcx>;
-    type RegionOutlivesPredicate = ty::RegionOutlivesPredicate<'tcx>;
-    type TypeOutlivesPredicate = ty::TypeOutlivesPredicate<'tcx>;
-    type ProjectionPredicate = ty::ProjectionPredicate<'tcx>;
-    type NormalizesTo = ty::NormalizesTo<'tcx>;
-    type SubtypePredicate = ty::SubtypePredicate<'tcx>;
-    type CoercePredicate = ty::CoercePredicate<'tcx>;
-    type ClosureKind = ty::ClosureKind;
+    type Clause = Clause<'tcx>;
+
     type Clauses = ty::Clauses<'tcx>;
 
     fn mk_canonical_var_infos(self, infos: &[ty::CanonicalVarInfo<Self>]) -> Self::CanonicalVars {
         self.mk_canonical_var_infos(infos)
     }
+
+    type GenericsOf = &'tcx ty::Generics;
+
+    fn generics_of(self, def_id: DefId) -> &'tcx ty::Generics {
+        self.generics_of(def_id)
+    }
+
+    fn type_of_instantiated(self, def_id: DefId, args: ty::GenericArgsRef<'tcx>) -> Ty<'tcx> {
+        self.type_of(def_id).instantiate(self, args)
+    }
+
+    fn alias_ty_kind(self, alias: ty::AliasTy<'tcx>) -> ty::AliasTyKind {
+        match self.def_kind(alias.def_id) {
+            DefKind::AssocTy => {
+                if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
+                {
+                    ty::Inherent
+                } else {
+                    ty::Projection
+                }
+            }
+            DefKind::OpaqueTy => ty::Opaque,
+            DefKind::TyAlias => ty::Weak,
+            kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
+        }
+    }
+
+    fn alias_term_kind(self, alias: ty::AliasTerm<'tcx>) -> ty::AliasTermKind {
+        match self.def_kind(alias.def_id) {
+            DefKind::AssocTy => {
+                if let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(alias.def_id))
+                {
+                    ty::AliasTermKind::InherentTy
+                } else {
+                    ty::AliasTermKind::ProjectionTy
+                }
+            }
+            DefKind::OpaqueTy => ty::AliasTermKind::OpaqueTy,
+            DefKind::TyAlias => ty::AliasTermKind::WeakTy,
+            DefKind::AssocConst => ty::AliasTermKind::ProjectionConst,
+            DefKind::AnonConst => ty::AliasTermKind::UnevaluatedConst,
+            kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
+        }
+    }
+
+    fn trait_ref_and_own_args_for_alias(
+        self,
+        def_id: Self::DefId,
+        args: Self::GenericArgs,
+    ) -> (rustc_type_ir::TraitRef<Self>, Self::OwnItemArgs) {
+        assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst);
+        let trait_def_id = self.parent(def_id);
+        assert_matches!(self.def_kind(trait_def_id), DefKind::Trait);
+        let trait_generics = self.generics_of(trait_def_id);
+        (
+            ty::TraitRef::new(self, trait_def_id, args.truncate_to(self, trait_generics)),
+            &args[trait_generics.count()..],
+        )
+    }
+
+    fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs {
+        self.mk_args(args)
+    }
+
+    fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs {
+        self.mk_args_from_iter(args)
+    }
+
+    fn check_and_mk_args(
+        self,
+        def_id: DefId,
+        args: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
+    ) -> ty::GenericArgsRef<'tcx> {
+        self.check_and_mk_args(def_id, args)
+    }
+
+    fn parent(self, def_id: Self::DefId) -> Self::DefId {
+        self.parent(def_id)
+    }
+
+    fn recursion_limit(self) -> usize {
+        self.recursion_limit().0
+    }
+}
+
+impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for abi::Abi {
+    fn is_rust(self) -> bool {
+        matches!(self, abi::Abi::Rust)
+    }
+}
+
+impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety {
+    fn is_safe(self) -> bool {
+        matches!(self, hir::Safety::Safe)
+    }
+
+    fn prefix_str(self) -> &'static str {
+        self.prefix_str()
+    }
 }
 
 type InternedSet<'tcx, T> = ShardedHashMap<InternedInSet<'tcx, T>, ()>;
@@ -917,7 +1020,7 @@
         )
     }
 
-    pub fn lift<T: Lift<'tcx>>(self, value: T) -> Option<T::Lifted> {
+    pub fn lift<T: Lift<TyCtxt<'tcx>>>(self, value: T) -> Option<T::Lifted> {
         value.lift_to_tcx(self)
     }
 
@@ -1524,31 +1627,9 @@
     }
 }
 
-/// A trait implemented for all `X<'a>` types that can be safely and
-/// efficiently converted to `X<'tcx>` as long as they are part of the
-/// provided `TyCtxt<'tcx>`.
-/// This can be done, for example, for `Ty<'tcx>` or `GenericArgsRef<'tcx>`
-/// by looking them up in their respective interners.
-///
-/// However, this is still not the best implementation as it does
-/// need to compare the components, even for interned values.
-/// It would be more efficient if `TypedArena` provided a way to
-/// determine whether the address is in the allocated range.
-///
-/// `None` is returned if the value or one of the components is not part
-/// of the provided context.
-/// For `Ty`, `None` can be returned if either the type interner doesn't
-/// contain the `TyKind` key or if the address of the interned
-/// pointer differs. The latter case is possible if a primitive type,
-/// e.g., `()` or `u8`, was interned in a different context.
-pub trait Lift<'tcx>: fmt::Debug {
-    type Lifted: fmt::Debug + 'tcx;
-    fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted>;
-}
-
 macro_rules! nop_lift {
     ($set:ident; $ty:ty => $lifted:ty) => {
-        impl<'a, 'tcx> Lift<'tcx> for $ty {
+        impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for $ty {
             type Lifted = $lifted;
             fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
                 // Assert that the set has the right type.
@@ -1583,7 +1664,7 @@
 
 macro_rules! nop_list_lift {
     ($set:ident; $ty:ty => $lifted:ty) => {
-        impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> {
+        impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for &'a List<$ty> {
             type Lifted = &'tcx List<$lifted>;
             fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
                 // Assert that the set has the right type.
@@ -1621,7 +1702,7 @@
 
 macro_rules! nop_slice_lift {
     ($ty:ty => $lifted:ty) => {
-        impl<'a, 'tcx> Lift<'tcx> for &'a [$ty] {
+        impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for &'a [$ty] {
             type Lifted = &'tcx [$lifted];
             fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
                 if self.is_empty() {
@@ -1945,11 +2026,8 @@
     /// that is, a `fn` type that is equivalent in every way for being
     /// unsafe.
     pub fn safe_to_unsafe_fn_ty(self, sig: PolyFnSig<'tcx>) -> Ty<'tcx> {
-        assert_eq!(sig.unsafety(), hir::Unsafety::Normal);
-        Ty::new_fn_ptr(
-            self,
-            sig.map_bound(|sig| ty::FnSig { unsafety: hir::Unsafety::Unsafe, ..sig }),
-        )
+        assert_eq!(sig.safety(), hir::Safety::Safe);
+        Ty::new_fn_ptr(self, sig.map_bound(|sig| ty::FnSig { safety: hir::Safety::Unsafe, ..sig }))
     }
 
     /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name`
@@ -2006,20 +2084,16 @@
     /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then
     /// you would get a `fn(u32, i32)`.
     /// `unsafety` determines the unsafety of the fn signature. If you pass
-    /// `hir::Unsafety::Unsafe` in the previous example, then you would get
+    /// `hir::Safety::Unsafe` in the previous example, then you would get
     /// an `unsafe fn (u32, i32)`.
     /// It cannot convert a closure that requires unsafe.
-    pub fn signature_unclosure(
-        self,
-        sig: PolyFnSig<'tcx>,
-        unsafety: hir::Unsafety,
-    ) -> PolyFnSig<'tcx> {
+    pub fn signature_unclosure(self, sig: PolyFnSig<'tcx>, safety: hir::Safety) -> PolyFnSig<'tcx> {
         sig.map_bound(|s| {
             let params = match s.inputs()[0].kind() {
                 ty::Tuple(params) => *params,
                 _ => bug!(),
             };
-            self.mk_fn_sig(params, s.output(), s.c_variadic, unsafety, abi::Abi::Rust)
+            self.mk_fn_sig(params, s.output(), s.c_variadic, safety, abi::Abi::Rust)
         })
     }
 
@@ -2060,7 +2134,7 @@
             && let DefKind::AssocTy = self.def_kind(def_id)
             && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(def_id))
         {
-            if generics.params.len() + 1 != args.len() {
+            if generics.own_params.len() + 1 != args.len() {
                 return false;
             }
 
@@ -2085,7 +2159,7 @@
             own_args
         };
 
-        for (param, arg) in std::iter::zip(&generics.params, own_args) {
+        for (param, arg) in std::iter::zip(&generics.own_params, own_args) {
             match (&param.kind, arg.unpack()) {
                 (ty::GenericParamDefKind::Type { .. }, ty::GenericArgKind::Type(_))
                 | (ty::GenericParamDefKind::Lifetime, ty::GenericArgKind::Lifetime(_))
@@ -2286,7 +2360,7 @@
         inputs: I,
         output: I::Item,
         c_variadic: bool,
-        unsafety: hir::Unsafety,
+        safety: hir::Safety,
         abi: abi::Abi,
     ) -> T::Output
     where
@@ -2296,7 +2370,7 @@
         T::collect_and_apply(inputs.into_iter().chain(iter::once(output)), |xs| ty::FnSig {
             inputs_and_output: self.mk_type_list(xs),
             c_variadic,
-            unsafety,
+            safety,
             abi,
         })
     }
@@ -2331,7 +2405,7 @@
     pub fn mk_args_from_iter<I, T>(self, iter: I) -> T::Output
     where
         I: Iterator<Item = T>,
-        T: CollectAndApply<GenericArg<'tcx>, &'tcx List<GenericArg<'tcx>>>,
+        T: CollectAndApply<GenericArg<'tcx>, ty::GenericArgsRef<'tcx>>,
     {
         T::collect_and_apply(iter, |xs| self.mk_args(xs))
     }
@@ -2449,7 +2523,7 @@
                     span,
                     msg,
                     format!("#![feature({feature})]\n"),
-                    Applicability::MachineApplicable,
+                    Applicability::MaybeIncorrect,
                 );
             } else {
                 diag.help(msg);
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 71437ce..99d703b 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -34,7 +34,7 @@
     Mismatch,
     ConstnessMismatch(ExpectedFound<ty::BoundConstness>),
     PolarityMismatch(ExpectedFound<ty::PredicatePolarity>),
-    UnsafetyMismatch(ExpectedFound<hir::Unsafety>),
+    SafetyMismatch(ExpectedFound<hir::Safety>),
     AbiMismatch(ExpectedFound<abi::Abi>),
     Mutability,
     ArgumentMutability(usize),
@@ -107,7 +107,7 @@
                 format!("expected {} polarity, found {} polarity", values.expected, values.found)
                     .into()
             }
-            UnsafetyMismatch(values) => {
+            SafetyMismatch(values) => {
                 format!("expected {} fn, found {} fn", values.expected, values.found).into()
             }
             AbiMismatch(values) => {
@@ -204,7 +204,7 @@
     pub fn must_include_note(self) -> bool {
         use self::TypeError::*;
         match self {
-            CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | ConstnessMismatch(_)
+            CyclicTy(_) | CyclicConst(_) | SafetyMismatch(_) | ConstnessMismatch(_)
             | PolarityMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_)
             | ArgumentSorts(..) | Sorts(_) | IntMismatch(_) | FloatMismatch(_)
             | VariadicMismatch(_) | TargetFeatureCast(_) => false,
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 8d7489f..7508f00 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -281,13 +281,13 @@
             }
             ty::FnPtr(obl_sig) => match k {
                 ty::FnPtr(impl_sig) => {
-                    let ty::FnSig { inputs_and_output, c_variadic, unsafety, abi } =
+                    let ty::FnSig { inputs_and_output, c_variadic, safety, abi } =
                         obl_sig.skip_binder();
                     let impl_sig = impl_sig.skip_binder();
 
                     abi == impl_sig.abi
                         && c_variadic == impl_sig.c_variadic
-                        && unsafety == impl_sig.unsafety
+                        && safety == impl_sig.safety
                         && inputs_and_output.len() == impl_sig.inputs_and_output.len()
                         && iter::zip(inputs_and_output, impl_sig.inputs_and_output)
                             .all(|(obl, imp)| self.types_may_unify(obl, imp))
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 0dc8356..4de7d53 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -294,10 +294,10 @@
                 self.add_ty(b);
             }
             ty::PredicateKind::Clause(ty::ClauseKind::Projection(ty::ProjectionPredicate {
-                projection_ty,
+                projection_term,
                 term,
             })) => {
-                self.add_alias_ty(projection_ty);
+                self.add_alias_term(projection_term);
                 self.add_term(term);
             }
             ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
@@ -313,7 +313,7 @@
             }
             ty::PredicateKind::Ambiguous => {}
             ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term }) => {
-                self.add_alias_ty(alias);
+                self.add_alias_term(alias);
                 self.add_term(term);
             }
             ty::PredicateKind::AliasRelate(t1, t2, _) => {
@@ -410,6 +410,10 @@
         self.add_args(alias_ty.args);
     }
 
+    fn add_alias_term(&mut self, alias_term: ty::AliasTerm<'_>) {
+        self.add_args(alias_term.args);
+    }
+
     fn add_args(&mut self, args: &[GenericArg<'_>]) {
         for kind in args {
             match kind.unpack() {
diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs
index de2c01c..cb11bb3 100644
--- a/compiler/rustc_middle/src/ty/generic_args.rs
+++ b/compiler/rustc_middle/src/ty/generic_args.rs
@@ -11,6 +11,7 @@
 use rustc_data_structures::intern::Interned;
 use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_hir::def_id::DefId;
+use rustc_macros::extension;
 use rustc_macros::{
     Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable,
 };
@@ -25,6 +26,9 @@
 use std::ops::Deref;
 use std::ptr::NonNull;
 
+pub type GenericArgKind<'tcx> = rustc_type_ir::GenericArgKind<TyCtxt<'tcx>>;
+pub type TermKind<'tcx> = rustc_type_ir::TermKind<TyCtxt<'tcx>>;
+
 /// An entity in the Rust type system, which can be one of
 /// several kinds (types, lifetimes, and consts).
 /// To reduce memory usage, a `GenericArg` is an interned pointer,
@@ -39,6 +43,32 @@
     marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>,
 }
 
+impl<'tcx> rustc_type_ir::inherent::GenericArgs<TyCtxt<'tcx>> for ty::GenericArgsRef<'tcx> {
+    fn type_at(self, i: usize) -> Ty<'tcx> {
+        self.type_at(i)
+    }
+
+    fn identity_for_item(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::GenericArgsRef<'tcx> {
+        GenericArgs::identity_for_item(tcx, def_id)
+    }
+
+    fn extend_with_error(
+        tcx: TyCtxt<'tcx>,
+        def_id: DefId,
+        original_args: &[ty::GenericArg<'tcx>],
+    ) -> ty::GenericArgsRef<'tcx> {
+        ty::GenericArgs::extend_with_error(tcx, def_id, original_args)
+    }
+}
+
+impl<'tcx> rustc_type_ir::inherent::IntoKind for GenericArg<'tcx> {
+    type Kind = GenericArgKind<'tcx>;
+
+    fn kind(self) -> Self::Kind {
+        self.unpack()
+    }
+}
+
 #[cfg(parallel_compiler)]
 unsafe impl<'tcx> rustc_data_structures::sync::DynSend for GenericArg<'tcx> where
     &'tcx (Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>): rustc_data_structures::sync::DynSend
@@ -69,13 +99,7 @@
 const REGION_TAG: usize = 0b01;
 const CONST_TAG: usize = 0b10;
 
-#[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, HashStable)]
-pub enum GenericArgKind<'tcx> {
-    Lifetime(ty::Region<'tcx>),
-    Type(Ty<'tcx>),
-    Const(ty::Const<'tcx>),
-}
-
+#[extension(trait GenericArgPackExt<'tcx>)]
 impl<'tcx> GenericArgKind<'tcx> {
     #[inline]
     fn pack(self) -> GenericArg<'tcx> {
@@ -205,7 +229,7 @@
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for GenericArg<'a> {
+impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for GenericArg<'a> {
     type Lifted = GenericArg<'tcx>;
 
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
@@ -359,8 +383,8 @@
     ) where
         F: FnMut(&ty::GenericParamDef, &[GenericArg<'tcx>]) -> GenericArg<'tcx>,
     {
-        args.reserve(defs.params.len());
-        for param in &defs.params {
+        args.reserve(defs.own_params.len());
+        for param in &defs.own_params {
             let kind = mk_kind(param, args);
             assert_eq!(param.index as usize, args.len(), "{args:#?}, {defs:#?}");
             args.push(kind);
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index 6bf2051..cfaca05 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -132,7 +132,7 @@
 pub struct Generics {
     pub parent: Option<DefId>,
     pub parent_count: usize,
-    pub params: Vec<GenericParamDef>,
+    pub own_params: Vec<GenericParamDef>,
 
     /// Reverse map to the `index` field of each `GenericParamDef`.
     #[stable_hasher(ignore)]
@@ -145,6 +145,12 @@
     pub host_effect_index: Option<usize>,
 }
 
+impl<'tcx> rustc_type_ir::inherent::GenericsOf<TyCtxt<'tcx>> for &'tcx Generics {
+    fn count(&self) -> usize {
+        self.parent_count + self.own_params.len()
+    }
+}
+
 impl<'tcx> Generics {
     /// Looks through the generics and all parents to find the index of the
     /// given param def-id. This is in comparison to the `param_def_id_to_index`
@@ -163,7 +169,7 @@
 
     #[inline]
     pub fn count(&self) -> usize {
-        self.parent_count + self.params.len()
+        self.parent_count + self.own_params.len()
     }
 
     pub fn own_counts(&self) -> GenericParamCount {
@@ -172,7 +178,7 @@
         // presence of this method will be a constant reminder.
         let mut own_counts = GenericParamCount::default();
 
-        for param in &self.params {
+        for param in &self.own_params {
             match param.kind {
                 GenericParamDefKind::Lifetime => own_counts.lifetimes += 1,
                 GenericParamDefKind::Type { .. } => own_counts.types += 1,
@@ -186,7 +192,7 @@
     pub fn own_defaults(&self) -> GenericParamCount {
         let mut own_defaults = GenericParamCount::default();
 
-        for param in &self.params {
+        for param in &self.own_params {
             match param.kind {
                 GenericParamDefKind::Lifetime => (),
                 GenericParamDefKind::Type { has_default, .. } => {
@@ -215,7 +221,7 @@
     }
 
     pub fn own_requires_monomorphization(&self) -> bool {
-        for param in &self.params {
+        for param in &self.own_params {
             match param.kind {
                 GenericParamDefKind::Type { .. }
                 | GenericParamDefKind::Const { is_host_effect: false, .. } => {
@@ -231,7 +237,7 @@
     /// Returns the `GenericParamDef` with the given index.
     pub fn param_at(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx GenericParamDef {
         if let Some(index) = param_index.checked_sub(self.parent_count) {
-            &self.params[index]
+            &self.own_params[index]
         } else {
             tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
                 .param_at(param_index, tcx)
@@ -245,7 +251,7 @@
         tcx: TyCtxt<'tcx>,
     ) -> Option<&'tcx GenericParamDef> {
         if let Some(index) = param_index.checked_sub(self.parent_count) {
-            self.params.get(index)
+            self.own_params.get(index)
         } else {
             tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
                 .opt_param_at(param_index, tcx)
@@ -254,7 +260,7 @@
 
     pub fn params_to(&'tcx self, param_index: usize, tcx: TyCtxt<'tcx>) -> &'tcx [GenericParamDef] {
         if let Some(index) = param_index.checked_sub(self.parent_count) {
-            &self.params[..index]
+            &self.own_params[..index]
         } else {
             tcx.generics_of(self.parent.expect("parent_count > 0 but no parent?"))
                 .params_to(param_index, tcx)
@@ -308,7 +314,7 @@
 
     /// Returns `true` if `params` has `impl Trait`.
     pub fn has_impl_trait(&'tcx self) -> bool {
-        self.params.iter().any(|param| {
+        self.own_params.iter().any(|param| {
             matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
         })
     }
@@ -336,7 +342,7 @@
         // good enough for now as this should only be used
         // for diagnostics anyways.
         own_params.end -= self
-            .params
+            .own_params
             .iter()
             .rev()
             .take_while(|param| {
@@ -358,7 +364,7 @@
         &'tcx self,
         args: &'tcx [ty::GenericArg<'tcx>],
     ) -> &'tcx [ty::GenericArg<'tcx>] {
-        let own = &args[self.parent_count..][..self.params.len()];
+        let own = &args[self.parent_count..][..self.own_params.len()];
         if self.has_self && self.parent.is_none() { &own[1..] } else { own }
     }
 
@@ -372,7 +378,7 @@
         args: &'tcx [ty::GenericArg<'tcx>],
     ) -> bool {
         let mut default_param_seen = false;
-        for param in self.params.iter() {
+        for param in self.own_params.iter() {
             if let Some(inst) =
                 param.default_value(tcx).map(|default| default.instantiate(tcx, args))
             {
@@ -385,6 +391,14 @@
         }
         false
     }
+
+    pub fn is_empty(&'tcx self) -> bool {
+        self.count() == 0
+    }
+
+    pub fn is_own_empty(&'tcx self) -> bool {
+        self.own_params.is_empty()
+    }
 }
 
 /// Bounds on generics.
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index f8490e5..cf701f8 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -114,16 +114,35 @@
     }
 }
 
+#[extension(pub trait FloatExt)]
+impl Float {
+    #[inline]
+    fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
+        match *self {
+            F16 => tcx.types.f16,
+            F32 => tcx.types.f32,
+            F64 => tcx.types.f64,
+            F128 => tcx.types.f128,
+        }
+    }
+
+    fn from_float_ty(fty: ty::FloatTy) -> Self {
+        match fty {
+            ty::FloatTy::F16 => F16,
+            ty::FloatTy::F32 => F32,
+            ty::FloatTy::F64 => F64,
+            ty::FloatTy::F128 => F128,
+        }
+    }
+}
+
 #[extension(pub trait PrimitiveExt)]
 impl Primitive {
     #[inline]
     fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
         match *self {
             Int(i, signed) => i.to_ty(tcx, signed),
-            F16 => tcx.types.f16,
-            F32 => tcx.types.f32,
-            F64 => tcx.types.f64,
-            F128 => tcx.types.f128,
+            Float(f) => f.to_ty(tcx),
             // FIXME(erikdesjardins): handle non-default addrspace ptr sizes
             Pointer(_) => Ty::new_mut_ptr(tcx, tcx.types.unit),
         }
@@ -140,7 +159,7 @@
                 let signed = false;
                 tcx.data_layout().ptr_sized_integer().to_ty(tcx, signed)
             }
-            F16 | F32 | F64 | F128 => bug!("floats do not have an int type"),
+            Float(_) => bug!("floats do not have an int type"),
         }
     }
 }
@@ -333,7 +352,23 @@
         match *ty.kind() {
             ty::Ref(_, pointee, _) | ty::RawPtr(pointee, _) => {
                 let non_zero = !ty.is_unsafe_ptr();
-                let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
+
+                let tail = tcx.struct_tail_with_normalize(
+                    pointee,
+                    |ty| match tcx.try_normalize_erasing_regions(param_env, ty) {
+                        Ok(ty) => ty,
+                        Err(e) => Ty::new_error_with_message(
+                            tcx,
+                            DUMMY_SP,
+                            format!(
+                                "normalization failed for {} but no errors reported",
+                                e.get_type_for_failure()
+                            ),
+                        ),
+                    },
+                    || {},
+                );
+
                 match tail.kind() {
                     ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => {
                         debug_assert!(tail.has_non_region_param());
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 73b20f0..f274098 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -28,7 +28,7 @@
 use crate::ty::util::Discr;
 pub use adt::*;
 pub use assoc::*;
-pub use generic_args::*;
+pub use generic_args::{GenericArgKind, TermKind, *};
 pub use generics::*;
 pub use intrinsic::IntrinsicDef;
 use rustc_ast as ast;
@@ -48,7 +48,8 @@
 use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
 use rustc_index::IndexVec;
 use rustc_macros::{
-    Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable,
+    extension, Decodable, Encodable, HashStable, TyDecodable, TyEncodable, TypeFoldable,
+    TypeVisitable,
 };
 use rustc_query_system::ich::StableHashingContext;
 use rustc_serialize::{Decodable, Encodable};
@@ -96,13 +97,13 @@
 pub use self::parameterized::ParameterizedOverTcx;
 pub use self::pattern::{Pattern, PatternKind};
 pub use self::predicate::{
-    Clause, ClauseKind, CoercePredicate, ExistentialPredicate, ExistentialProjection,
-    ExistentialTraitRef, NormalizesTo, OutlivesPredicate, PolyCoercePredicate,
-    PolyExistentialPredicate, PolyExistentialProjection, PolyExistentialTraitRef,
-    PolyProjectionPredicate, PolyRegionOutlivesPredicate, PolySubtypePredicate, PolyTraitPredicate,
-    PolyTraitRef, PolyTypeOutlivesPredicate, Predicate, PredicateKind, ProjectionPredicate,
-    RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitPredicate,
-    TraitRef, TypeOutlivesPredicate,
+    AliasTerm, Clause, ClauseKind, CoercePredicate, ExistentialPredicate,
+    ExistentialPredicateStableCmpExt, ExistentialProjection, ExistentialTraitRef, NormalizesTo,
+    OutlivesPredicate, PolyCoercePredicate, PolyExistentialPredicate, PolyExistentialProjection,
+    PolyExistentialTraitRef, PolyProjectionPredicate, PolyRegionOutlivesPredicate,
+    PolySubtypePredicate, PolyTraitPredicate, PolyTraitRef, PolyTypeOutlivesPredicate, Predicate,
+    PredicateKind, ProjectionPredicate, RegionOutlivesPredicate, SubtypePredicate, ToPolyTraitRef,
+    TraitPredicate, TraitRef, TypeOutlivesPredicate,
 };
 pub use self::region::{
     BoundRegion, BoundRegionKind, BoundRegionKind::*, EarlyParamRegion, LateParamRegion, Region,
@@ -266,7 +267,7 @@
 pub struct ImplTraitHeader<'tcx> {
     pub trait_ref: ty::EarlyBinder<ty::TraitRef<'tcx>>,
     pub polarity: ImplPolarity,
-    pub unsafety: hir::Unsafety,
+    pub safety: hir::Safety,
 }
 
 #[derive(Copy, Clone, PartialEq, Eq, Debug, TypeFoldable, TypeVisitable)]
@@ -277,61 +278,6 @@
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)]
 #[derive(TypeFoldable, TypeVisitable)]
-pub enum ImplPolarity {
-    /// `impl Trait for Type`
-    Positive,
-    /// `impl !Trait for Type`
-    Negative,
-    /// `#[rustc_reservation_impl] impl Trait for Type`
-    ///
-    /// This is a "stability hack", not a real Rust feature.
-    /// See #64631 for details.
-    Reservation,
-}
-
-impl fmt::Display for ImplPolarity {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Self::Positive => f.write_str("positive"),
-            Self::Negative => f.write_str("negative"),
-            Self::Reservation => f.write_str("reservation"),
-        }
-    }
-}
-
-/// Polarity for a trait predicate. May either be negative or positive.
-/// Distinguished from [`ImplPolarity`] since we never compute goals with
-/// "reservation" level.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)]
-#[derive(TypeFoldable, TypeVisitable)]
-pub enum PredicatePolarity {
-    /// `Type: Trait`
-    Positive,
-    /// `Type: !Trait`
-    Negative,
-}
-
-impl PredicatePolarity {
-    /// Flips polarity by turning `Positive` into `Negative` and `Negative` into `Positive`.
-    pub fn flip(&self) -> PredicatePolarity {
-        match self {
-            PredicatePolarity::Positive => PredicatePolarity::Negative,
-            PredicatePolarity::Negative => PredicatePolarity::Positive,
-        }
-    }
-}
-
-impl fmt::Display for PredicatePolarity {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            Self::Positive => f.write_str("positive"),
-            Self::Negative => f.write_str("negative"),
-        }
-    }
-}
-
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable, Debug)]
-#[derive(TypeFoldable, TypeVisitable)]
 pub enum Asyncness {
     Yes,
     No,
@@ -530,7 +476,7 @@
 #[rustc_pass_by_value]
 pub struct Ty<'tcx>(Interned<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>);
 
-impl<'tcx> IntoKind for Ty<'tcx> {
+impl<'tcx> rustc_type_ir::inherent::IntoKind for Ty<'tcx> {
     type Kind = TyKind<'tcx>;
 
     fn kind(self) -> TyKind<'tcx> {
@@ -576,6 +522,14 @@
     marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>,
 }
 
+impl<'tcx> rustc_type_ir::inherent::IntoKind for Term<'tcx> {
+    type Kind = TermKind<'tcx>;
+
+    fn kind(self) -> Self::Kind {
+        self.unpack()
+    }
+}
+
 #[cfg(parallel_compiler)]
 unsafe impl<'tcx> rustc_data_structures::sync::DynSend for Term<'tcx> where
     &'tcx (Ty<'tcx>, Const<'tcx>): rustc_data_structures::sync::DynSend
@@ -591,14 +545,10 @@
 
 impl Debug for Term<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let data = if let Some(ty) = self.ty() {
-            format!("Term::Ty({ty:?})")
-        } else if let Some(ct) = self.ct() {
-            format!("Term::Ct({ct:?})")
-        } else {
-            unreachable!()
-        };
-        f.write_str(&data)
+        match self.unpack() {
+            TermKind::Ty(ty) => write!(f, "Term::Ty({ty:?})"),
+            TermKind::Const(ct) => write!(f, "Term::Const({ct:?})"),
+        }
     }
 }
 
@@ -625,13 +575,19 @@
         self,
         folder: &mut F,
     ) -> Result<Self, F::Error> {
-        Ok(self.unpack().try_fold_with(folder)?.pack())
+        match self.unpack() {
+            ty::TermKind::Ty(ty) => ty.try_fold_with(folder).map(Into::into),
+            ty::TermKind::Const(ct) => ct.try_fold_with(folder).map(Into::into),
+        }
     }
 }
 
 impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for Term<'tcx> {
     fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
-        self.unpack().visit_with(visitor)
+        match self.unpack() {
+            ty::TermKind::Ty(ty) => ty.visit_with(visitor),
+            ty::TermKind::Const(ct) => ct.visit_with(visitor),
+        }
     }
 }
 
@@ -684,15 +640,14 @@
         }
     }
 
-    /// This function returns the inner `AliasTy` for a `ty::Alias` or `ConstKind::Unevaluated`.
-    pub fn to_alias_ty(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> {
+    pub fn to_alias_term(self) -> Option<AliasTerm<'tcx>> {
         match self.unpack() {
             TermKind::Ty(ty) => match *ty.kind() {
-                ty::Alias(_kind, alias_ty) => Some(alias_ty),
+                ty::Alias(_kind, alias_ty) => Some(alias_ty.into()),
                 _ => None,
             },
             TermKind::Const(ct) => match ct.kind() {
-                ConstKind::Unevaluated(uv) => Some(AliasTy::new(tcx, uv.def, uv.args)),
+                ConstKind::Unevaluated(uv) => Some(uv.into()),
                 _ => None,
             },
         }
@@ -710,13 +665,7 @@
 const TYPE_TAG: usize = 0b00;
 const CONST_TAG: usize = 0b01;
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable)]
-pub enum TermKind<'tcx> {
-    Ty(Ty<'tcx>),
-    Const(Const<'tcx>),
-}
-
+#[extension(pub trait TermKindPackExt<'tcx>)]
 impl<'tcx> TermKind<'tcx> {
     #[inline]
     fn pack(self) -> Term<'tcx> {
@@ -981,7 +930,7 @@
 
 pub type PlaceholderRegion = Placeholder<BoundRegion>;
 
-impl PlaceholderLike for PlaceholderRegion {
+impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderRegion {
     fn universe(self) -> UniverseIndex {
         self.universe
     }
@@ -1001,7 +950,7 @@
 
 pub type PlaceholderType = Placeholder<BoundTy>;
 
-impl PlaceholderLike for PlaceholderType {
+impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderType {
     fn universe(self) -> UniverseIndex {
         self.universe
     }
@@ -1028,7 +977,7 @@
 
 pub type PlaceholderConst = Placeholder<BoundVar>;
 
-impl PlaceholderLike for PlaceholderConst {
+impl rustc_type_ir::inherent::PlaceholderLike for PlaceholderConst {
     fn universe(self) -> UniverseIndex {
         self.universe
     }
@@ -1865,6 +1814,11 @@
         self.get_attrs(did, attr).next().is_some()
     }
 
+    /// Determines whether an item is annotated with a multi-segement attribute
+    pub fn has_attrs_with_path(self, did: impl Into<DefId>, attrs: &[Symbol]) -> bool {
+        self.get_attrs_by_path(did.into(), attrs).next().is_some()
+    }
+
     /// Returns `true` if this is an `auto trait`.
     pub fn trait_is_auto(self, trait_def_id: DefId) -> bool {
         self.trait_def(trait_def_id).has_auto_impl
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 791f27a..115cf3e 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -100,8 +100,7 @@
     /// codegen, we need to normalize the contents.
     // FIXME(@lcnr): This method should not be necessary, we now normalize
     // inside of binders. We should be able to only use
-    // `tcx.instantiate_bound_regions_with_erased`. Same for the `try_X`
-    // variant.
+    // `tcx.instantiate_bound_regions_with_erased`.
     #[tracing::instrument(level = "debug", skip(self, param_env))]
     pub fn normalize_erasing_late_bound_regions<T>(
         self,
@@ -115,26 +114,6 @@
         self.normalize_erasing_regions(param_env, value)
     }
 
-    /// If you have a `Binder<'tcx, T>`, you can do this to strip out the
-    /// late-bound regions and then normalize the result, yielding up
-    /// a `T` (with regions erased). This is appropriate when the
-    /// binder is being instantiated at the call site.
-    ///
-    /// N.B., currently, higher-ranked type bounds inhibit
-    /// normalization. Therefore, each time we erase them in
-    /// codegen, we need to normalize the contents.
-    pub fn try_normalize_erasing_late_bound_regions<T>(
-        self,
-        param_env: ty::ParamEnv<'tcx>,
-        value: ty::Binder<'tcx, T>,
-    ) -> Result<T, NormalizationError<'tcx>>
-    where
-        T: TypeFoldable<TyCtxt<'tcx>>,
-    {
-        let value = self.instantiate_bound_regions_with_erased(value);
-        self.try_normalize_erasing_regions(param_env, value)
-    }
-
     /// Monomorphizes a type from the AST by first applying the
     /// in-scope instantiations and then normalizing any associated
     /// types.
diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs
index 56dd525..293cc0a 100644
--- a/compiler/rustc_middle/src/ty/predicate.rs
+++ b/compiler/rustc_middle/src/ty/predicate.rs
@@ -1,22 +1,36 @@
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::intern::Interned;
-use rustc_errors::{DiagArgValue, IntoDiagArg};
 use rustc_hir::def_id::DefId;
-use rustc_hir::LangItem;
-use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable};
-use rustc_span::Span;
-use rustc_type_ir::ClauseKind as IrClauseKind;
-use rustc_type_ir::PredicateKind as IrPredicateKind;
+use rustc_macros::{extension, HashStable};
+use rustc_type_ir as ir;
 use std::cmp::Ordering;
 
-use crate::ty::visit::TypeVisitableExt;
 use crate::ty::{
-    self, AliasTy, Binder, DebruijnIndex, DebugWithInfcx, EarlyBinder, GenericArg, GenericArgs,
-    GenericArgsRef, PredicatePolarity, Term, Ty, TyCtxt, TypeFlags, WithCachedTypeInfo,
+    self, DebruijnIndex, EarlyBinder, PredicatePolarity, Ty, TyCtxt, TypeFlags, Upcast, UpcastFrom,
+    WithCachedTypeInfo,
 };
 
-pub type ClauseKind<'tcx> = IrClauseKind<TyCtxt<'tcx>>;
-pub type PredicateKind<'tcx> = IrPredicateKind<TyCtxt<'tcx>>;
+pub type TraitRef<'tcx> = ir::TraitRef<TyCtxt<'tcx>>;
+pub type AliasTerm<'tcx> = ir::AliasTerm<TyCtxt<'tcx>>;
+pub type ProjectionPredicate<'tcx> = ir::ProjectionPredicate<TyCtxt<'tcx>>;
+pub type ExistentialPredicate<'tcx> = ir::ExistentialPredicate<TyCtxt<'tcx>>;
+pub type ExistentialTraitRef<'tcx> = ir::ExistentialTraitRef<TyCtxt<'tcx>>;
+pub type ExistentialProjection<'tcx> = ir::ExistentialProjection<TyCtxt<'tcx>>;
+pub type TraitPredicate<'tcx> = ir::TraitPredicate<TyCtxt<'tcx>>;
+pub type ClauseKind<'tcx> = ir::ClauseKind<TyCtxt<'tcx>>;
+pub type PredicateKind<'tcx> = ir::PredicateKind<TyCtxt<'tcx>>;
+pub type NormalizesTo<'tcx> = ir::NormalizesTo<TyCtxt<'tcx>>;
+pub type CoercePredicate<'tcx> = ir::CoercePredicate<TyCtxt<'tcx>>;
+pub type SubtypePredicate<'tcx> = ir::SubtypePredicate<TyCtxt<'tcx>>;
+pub type OutlivesPredicate<'tcx, T> = ir::OutlivesPredicate<TyCtxt<'tcx>, T>;
+pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, ty::Region<'tcx>>;
+pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<'tcx, Ty<'tcx>>;
+pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
+pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>;
+pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>;
+pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>;
+pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
+pub type PolyProjectionPredicate<'tcx> = ty::Binder<'tcx, ProjectionPredicate<'tcx>>;
 
 /// A statement that can be proven by a trait solver. This includes things that may
 /// show up in where clauses, such as trait predicates and projection predicates,
@@ -30,6 +44,12 @@
     pub(super) Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
 );
 
+impl<'tcx> rustc_type_ir::inherent::Predicate<TyCtxt<'tcx>> for Predicate<'tcx> {
+    fn is_coinductive(self, interner: TyCtxt<'tcx>) -> bool {
+        self.is_coinductive(interner)
+    }
+}
+
 impl<'tcx> rustc_type_ir::visit::Flags for Predicate<'tcx> {
     fn flags(&self) -> TypeFlags {
         self.0.flags
@@ -142,6 +162,8 @@
     pub(super) Interned<'tcx, WithCachedTypeInfo<ty::Binder<'tcx, PredicateKind<'tcx>>>>,
 );
 
+impl<'tcx> rustc_type_ir::inherent::Clause<TyCtxt<'tcx>> for Clause<'tcx> {}
+
 impl<'tcx> Clause<'tcx> {
     pub fn as_predicate(self) -> Predicate<'tcx> {
         Predicate(self.0)
@@ -193,77 +215,31 @@
     }
 }
 
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub enum ExistentialPredicate<'tcx> {
-    /// E.g., `Iterator`.
-    Trait(ExistentialTraitRef<'tcx>),
-    /// E.g., `Iterator::Item = T`.
-    Projection(ExistentialProjection<'tcx>),
-    /// E.g., `Send`.
-    AutoTrait(DefId),
-}
-
-impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ExistentialPredicate<'tcx> {
-    fn fmt<Infcx: rustc_type_ir::InferCtxtLike<Interner = TyCtxt<'tcx>>>(
-        this: rustc_type_ir::WithInfcx<'_, Infcx, &Self>,
-        f: &mut std::fmt::Formatter<'_>,
-    ) -> std::fmt::Result {
-        std::fmt::Debug::fmt(&this.data, f)
-    }
-}
-
+#[extension(pub trait ExistentialPredicateStableCmpExt<'tcx>)]
 impl<'tcx> ExistentialPredicate<'tcx> {
     /// Compares via an ordering that will not change if modules are reordered or other changes are
     /// made to the tree. In particular, this ordering is preserved across incremental compilations.
-    pub fn stable_cmp(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Ordering {
-        use self::ExistentialPredicate::*;
+    fn stable_cmp(&self, tcx: TyCtxt<'tcx>, other: &Self) -> Ordering {
         match (*self, *other) {
-            (Trait(_), Trait(_)) => Ordering::Equal,
-            (Projection(ref a), Projection(ref b)) => {
+            (ExistentialPredicate::Trait(_), ExistentialPredicate::Trait(_)) => Ordering::Equal,
+            (ExistentialPredicate::Projection(ref a), ExistentialPredicate::Projection(ref b)) => {
                 tcx.def_path_hash(a.def_id).cmp(&tcx.def_path_hash(b.def_id))
             }
-            (AutoTrait(ref a), AutoTrait(ref b)) => {
+            (ExistentialPredicate::AutoTrait(ref a), ExistentialPredicate::AutoTrait(ref b)) => {
                 tcx.def_path_hash(*a).cmp(&tcx.def_path_hash(*b))
             }
-            (Trait(_), _) => Ordering::Less,
-            (Projection(_), Trait(_)) => Ordering::Greater,
-            (Projection(_), _) => Ordering::Less,
-            (AutoTrait(_), _) => Ordering::Greater,
+            (ExistentialPredicate::Trait(_), _) => Ordering::Less,
+            (ExistentialPredicate::Projection(_), ExistentialPredicate::Trait(_)) => {
+                Ordering::Greater
+            }
+            (ExistentialPredicate::Projection(_), _) => Ordering::Less,
+            (ExistentialPredicate::AutoTrait(_), _) => Ordering::Greater,
         }
     }
 }
 
 pub type PolyExistentialPredicate<'tcx> = ty::Binder<'tcx, ExistentialPredicate<'tcx>>;
 
-impl<'tcx> PolyExistentialPredicate<'tcx> {
-    /// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
-    /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self`
-    /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example).
-    pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::Clause<'tcx> {
-        match self.skip_binder() {
-            ExistentialPredicate::Trait(tr) => {
-                self.rebind(tr).with_self_ty(tcx, self_ty).to_predicate(tcx)
-            }
-            ExistentialPredicate::Projection(p) => {
-                self.rebind(p.with_self_ty(tcx, self_ty)).to_predicate(tcx)
-            }
-            ExistentialPredicate::AutoTrait(did) => {
-                let generics = tcx.generics_of(did);
-                let trait_ref = if generics.params.len() == 1 {
-                    ty::TraitRef::new(tcx, did, [self_ty])
-                } else {
-                    // If this is an ill-formed auto trait, then synthesize
-                    // new error args for the missing generics.
-                    let err_args = ty::GenericArgs::extend_with_error(tcx, did, &[self_ty.into()]);
-                    ty::TraitRef::new(tcx, did, err_args)
-                };
-                self.rebind(trait_ref).to_predicate(tcx)
-            }
-        }
-    }
-}
-
 impl<'tcx> ty::List<ty::PolyExistentialPredicate<'tcx>> {
     /// Returns the "principal `DefId`" of this set of existential predicates.
     ///
@@ -326,226 +302,10 @@
     }
 }
 
-/// A complete reference to a trait. These take numerous guises in syntax,
-/// but perhaps the most recognizable form is in a where-clause:
-/// ```ignore (illustrative)
-/// T: Foo<U>
-/// ```
-/// This would be represented by a trait-reference where the `DefId` is the
-/// `DefId` for the trait `Foo` and the args define `T` as parameter 0,
-/// and `U` as parameter 1.
-///
-/// Trait references also appear in object types like `Foo<U>`, but in
-/// that case the `Self` parameter is absent from the generic parameters.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct TraitRef<'tcx> {
-    pub def_id: DefId,
-    pub args: GenericArgsRef<'tcx>,
-    /// This field exists to prevent the creation of `TraitRef` without
-    /// calling [`TraitRef::new`].
-    pub(super) _use_trait_ref_new_instead: (),
-}
-
-impl<'tcx> TraitRef<'tcx> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        trait_def_id: DefId,
-        args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
-    ) -> Self {
-        let args = tcx.check_and_mk_args(trait_def_id, args);
-        Self { def_id: trait_def_id, args, _use_trait_ref_new_instead: () }
-    }
-
-    pub fn from_lang_item(
-        tcx: TyCtxt<'tcx>,
-        trait_lang_item: LangItem,
-        span: Span,
-        args: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
-    ) -> Self {
-        let trait_def_id = tcx.require_lang_item(trait_lang_item, Some(span));
-        Self::new(tcx, trait_def_id, args)
-    }
-
-    pub fn from_method(
-        tcx: TyCtxt<'tcx>,
-        trait_id: DefId,
-        args: GenericArgsRef<'tcx>,
-    ) -> ty::TraitRef<'tcx> {
-        let defs = tcx.generics_of(trait_id);
-        ty::TraitRef::new(tcx, trait_id, tcx.mk_args(&args[..defs.params.len()]))
-    }
-
-    /// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`
-    /// are the parameters defined on trait.
-    pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> TraitRef<'tcx> {
-        ty::TraitRef::new(tcx, def_id, GenericArgs::identity_for_item(tcx, def_id))
-    }
-
-    pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
-        ty::TraitRef::new(
-            tcx,
-            self.def_id,
-            [self_ty.into()].into_iter().chain(self.args.iter().skip(1)),
-        )
-    }
-
-    #[inline]
-    pub fn self_ty(&self) -> Ty<'tcx> {
-        self.args.type_at(0)
-    }
-}
-
 pub type PolyTraitRef<'tcx> = ty::Binder<'tcx, TraitRef<'tcx>>;
-
-impl<'tcx> PolyTraitRef<'tcx> {
-    pub fn self_ty(&self) -> ty::Binder<'tcx, Ty<'tcx>> {
-        self.map_bound_ref(|tr| tr.self_ty())
-    }
-
-    pub fn def_id(&self) -> DefId {
-        self.skip_binder().def_id
-    }
-}
-
-impl<'tcx> IntoDiagArg for TraitRef<'tcx> {
-    fn into_diag_arg(self) -> DiagArgValue {
-        self.to_string().into_diag_arg()
-    }
-}
-
-/// An existential reference to a trait, where `Self` is erased.
-/// For example, the trait object `Trait<'a, 'b, X, Y>` is:
-/// ```ignore (illustrative)
-/// exists T. T: Trait<'a, 'b, X, Y>
-/// ```
-/// The generic parameters don't include the erased `Self`, only trait
-/// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above).
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct ExistentialTraitRef<'tcx> {
-    pub def_id: DefId,
-    pub args: GenericArgsRef<'tcx>,
-}
-
-impl<'tcx> ExistentialTraitRef<'tcx> {
-    pub fn erase_self_ty(
-        tcx: TyCtxt<'tcx>,
-        trait_ref: ty::TraitRef<'tcx>,
-    ) -> ty::ExistentialTraitRef<'tcx> {
-        // Assert there is a Self.
-        trait_ref.args.type_at(0);
-
-        ty::ExistentialTraitRef {
-            def_id: trait_ref.def_id,
-            args: tcx.mk_args(&trait_ref.args[1..]),
-        }
-    }
-
-    /// Object types don't have a self type specified. Therefore, when
-    /// we convert the principal trait-ref into a normal trait-ref,
-    /// you must give *some* self type. A common choice is `mk_err()`
-    /// or some placeholder type.
-    pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::TraitRef<'tcx> {
-        // otherwise the escaping vars would be captured by the binder
-        // debug_assert!(!self_ty.has_escaping_bound_vars());
-
-        ty::TraitRef::new(tcx, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter()))
-    }
-}
-
-impl<'tcx> IntoDiagArg for ExistentialTraitRef<'tcx> {
-    fn into_diag_arg(self) -> DiagArgValue {
-        self.to_string().into_diag_arg()
-    }
-}
-
 pub type PolyExistentialTraitRef<'tcx> = ty::Binder<'tcx, ExistentialTraitRef<'tcx>>;
-
-impl<'tcx> PolyExistentialTraitRef<'tcx> {
-    pub fn def_id(&self) -> DefId {
-        self.skip_binder().def_id
-    }
-
-    /// Object types don't have a self type specified. Therefore, when
-    /// we convert the principal trait-ref into a normal trait-ref,
-    /// you must give *some* self type. A common choice is `mk_err()`
-    /// or some placeholder type.
-    pub fn with_self_ty(&self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ty::PolyTraitRef<'tcx> {
-        self.map_bound(|trait_ref| trait_ref.with_self_ty(tcx, self_ty))
-    }
-}
-
-/// A `ProjectionPredicate` for an `ExistentialTraitRef`.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct ExistentialProjection<'tcx> {
-    pub def_id: DefId,
-    pub args: GenericArgsRef<'tcx>,
-    pub term: Term<'tcx>,
-}
-
 pub type PolyExistentialProjection<'tcx> = ty::Binder<'tcx, ExistentialProjection<'tcx>>;
 
-impl<'tcx> ExistentialProjection<'tcx> {
-    /// Extracts the underlying existential trait reference from this projection.
-    /// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
-    /// then this function would return an `exists T. T: Iterator` existential trait
-    /// reference.
-    pub fn trait_ref(&self, tcx: TyCtxt<'tcx>) -> ty::ExistentialTraitRef<'tcx> {
-        let def_id = tcx.parent(self.def_id);
-        let args_count = tcx.generics_of(def_id).count() - 1;
-        let args = tcx.mk_args(&self.args[..args_count]);
-        ty::ExistentialTraitRef { def_id, args }
-    }
-
-    pub fn with_self_ty(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        self_ty: Ty<'tcx>,
-    ) -> ty::ProjectionPredicate<'tcx> {
-        // otherwise the escaping regions would be captured by the binders
-        debug_assert!(!self_ty.has_escaping_bound_vars());
-
-        ty::ProjectionPredicate {
-            projection_ty: AliasTy::new(
-                tcx,
-                self.def_id,
-                [self_ty.into()].into_iter().chain(self.args),
-            ),
-            term: self.term,
-        }
-    }
-
-    pub fn erase_self_ty(
-        tcx: TyCtxt<'tcx>,
-        projection_predicate: ty::ProjectionPredicate<'tcx>,
-    ) -> Self {
-        // Assert there is a Self.
-        projection_predicate.projection_ty.args.type_at(0);
-
-        Self {
-            def_id: projection_predicate.projection_ty.def_id,
-            args: tcx.mk_args(&projection_predicate.projection_ty.args[1..]),
-            term: projection_predicate.term,
-        }
-    }
-}
-
-impl<'tcx> PolyExistentialProjection<'tcx> {
-    pub fn with_self_ty(
-        &self,
-        tcx: TyCtxt<'tcx>,
-        self_ty: Ty<'tcx>,
-    ) -> ty::PolyProjectionPredicate<'tcx> {
-        self.map_bound(|p| p.with_self_ty(tcx, self_ty))
-    }
-
-    pub fn item_def_id(&self) -> DefId {
-        self.skip_binder().def_id
-    }
-}
-
 impl<'tcx> Clause<'tcx> {
     /// Performs a instantiation suitable for going from a
     /// poly-trait-ref to supertraits that must hold if that
@@ -652,183 +412,6 @@
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct TraitPredicate<'tcx> {
-    pub trait_ref: TraitRef<'tcx>,
-
-    /// If polarity is Positive: we are proving that the trait is implemented.
-    ///
-    /// If polarity is Negative: we are proving that a negative impl of this trait
-    /// exists. (Note that coherence also checks whether negative impls of supertraits
-    /// exist via a series of predicates.)
-    ///
-    /// If polarity is Reserved: that's a bug.
-    pub polarity: PredicatePolarity,
-}
-
-pub type PolyTraitPredicate<'tcx> = ty::Binder<'tcx, TraitPredicate<'tcx>>;
-
-impl<'tcx> TraitPredicate<'tcx> {
-    pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
-        Self { trait_ref: self.trait_ref.with_self_ty(tcx, self_ty), ..self }
-    }
-
-    pub fn def_id(self) -> DefId {
-        self.trait_ref.def_id
-    }
-
-    pub fn self_ty(self) -> Ty<'tcx> {
-        self.trait_ref.self_ty()
-    }
-}
-
-impl<'tcx> PolyTraitPredicate<'tcx> {
-    pub fn def_id(self) -> DefId {
-        // Ok to skip binder since trait `DefId` does not care about regions.
-        self.skip_binder().def_id()
-    }
-
-    pub fn self_ty(self) -> ty::Binder<'tcx, Ty<'tcx>> {
-        self.map_bound(|trait_ref| trait_ref.self_ty())
-    }
-
-    #[inline]
-    pub fn polarity(self) -> PredicatePolarity {
-        self.skip_binder().polarity
-    }
-}
-
-/// `A: B`
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct OutlivesPredicate<A, B>(pub A, pub B);
-pub type RegionOutlivesPredicate<'tcx> = OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>;
-pub type TypeOutlivesPredicate<'tcx> = OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>;
-pub type PolyRegionOutlivesPredicate<'tcx> = ty::Binder<'tcx, RegionOutlivesPredicate<'tcx>>;
-pub type PolyTypeOutlivesPredicate<'tcx> = ty::Binder<'tcx, TypeOutlivesPredicate<'tcx>>;
-
-/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates
-/// whether the `a` type is the type that we should label as "expected" when
-/// presenting user diagnostics.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct SubtypePredicate<'tcx> {
-    pub a_is_expected: bool,
-    pub a: Ty<'tcx>,
-    pub b: Ty<'tcx>,
-}
-pub type PolySubtypePredicate<'tcx> = ty::Binder<'tcx, SubtypePredicate<'tcx>>;
-
-/// Encodes that we have to coerce *from* the `a` type to the `b` type.
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct CoercePredicate<'tcx> {
-    pub a: Ty<'tcx>,
-    pub b: Ty<'tcx>,
-}
-pub type PolyCoercePredicate<'tcx> = ty::Binder<'tcx, CoercePredicate<'tcx>>;
-
-/// This kind of predicate has no *direct* correspondent in the
-/// syntax, but it roughly corresponds to the syntactic forms:
-///
-/// 1. `T: TraitRef<..., Item = Type>`
-/// 2. `<T as TraitRef<...>>::Item == Type` (NYI)
-///
-/// In particular, form #1 is "desugared" to the combination of a
-/// normal trait predicate (`T: TraitRef<...>`) and one of these
-/// predicates. Form #2 is a broader form in that it also permits
-/// equality between arbitrary types. Processing an instance of
-/// Form #2 eventually yields one of these `ProjectionPredicate`
-/// instances to normalize the LHS.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct ProjectionPredicate<'tcx> {
-    pub projection_ty: AliasTy<'tcx>,
-    pub term: Term<'tcx>,
-}
-
-impl<'tcx> ProjectionPredicate<'tcx> {
-    pub fn self_ty(self) -> Ty<'tcx> {
-        self.projection_ty.self_ty()
-    }
-
-    pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> ProjectionPredicate<'tcx> {
-        Self { projection_ty: self.projection_ty.with_self_ty(tcx, self_ty), ..self }
-    }
-
-    pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
-        self.projection_ty.trait_def_id(tcx)
-    }
-
-    pub fn def_id(self) -> DefId {
-        self.projection_ty.def_id
-    }
-}
-
-pub type PolyProjectionPredicate<'tcx> = Binder<'tcx, ProjectionPredicate<'tcx>>;
-
-impl<'tcx> PolyProjectionPredicate<'tcx> {
-    /// Returns the `DefId` of the trait of the associated item being projected.
-    #[inline]
-    pub fn trait_def_id(&self, tcx: TyCtxt<'tcx>) -> DefId {
-        self.skip_binder().projection_ty.trait_def_id(tcx)
-    }
-
-    /// Get the [PolyTraitRef] required for this projection to be well formed.
-    /// Note that for generic associated types the predicates of the associated
-    /// type also need to be checked.
-    #[inline]
-    pub fn required_poly_trait_ref(&self, tcx: TyCtxt<'tcx>) -> PolyTraitRef<'tcx> {
-        // Note: unlike with `TraitRef::to_poly_trait_ref()`,
-        // `self.0.trait_ref` is permitted to have escaping regions.
-        // This is because here `self` has a `Binder` and so does our
-        // return value, so we are preserving the number of binding
-        // levels.
-        self.map_bound(|predicate| predicate.projection_ty.trait_ref(tcx))
-    }
-
-    pub fn term(&self) -> Binder<'tcx, Term<'tcx>> {
-        self.map_bound(|predicate| predicate.term)
-    }
-
-    /// The `DefId` of the `TraitItem` for the associated type.
-    ///
-    /// Note that this is not the `DefId` of the `TraitRef` containing this
-    /// associated type, which is in `tcx.associated_item(projection_def_id()).container`.
-    pub fn projection_def_id(&self) -> DefId {
-        // Ok to skip binder since trait `DefId` does not care about regions.
-        self.skip_binder().projection_ty.def_id
-    }
-}
-
-/// Used by the new solver. Unlike a `ProjectionPredicate` this can only be
-/// proven by actually normalizing `alias`.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct NormalizesTo<'tcx> {
-    pub alias: AliasTy<'tcx>,
-    pub term: Term<'tcx>,
-}
-
-impl<'tcx> NormalizesTo<'tcx> {
-    pub fn self_ty(self) -> Ty<'tcx> {
-        self.alias.self_ty()
-    }
-
-    pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> NormalizesTo<'tcx> {
-        Self { alias: self.alias.with_self_ty(tcx, self_ty), ..self }
-    }
-
-    pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
-        self.alias.trait_def_id(tcx)
-    }
-
-    pub fn def_id(self) -> DefId {
-        self.alias.def_id
-    }
-}
-
 pub trait ToPolyTraitRef<'tcx> {
     fn to_poly_trait_ref(&self) -> PolyTraitRef<'tcx>;
 }
@@ -839,185 +422,162 @@
     }
 }
 
-pub trait ToPredicate<'tcx, P = Predicate<'tcx>> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> P;
-}
-
-impl<'tcx, T> ToPredicate<'tcx, T> for T {
-    fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> T {
-        self
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PredicateKind<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: PredicateKind<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        ty::Binder::dummy(from).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for PredicateKind<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        ty::Binder::dummy(self).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, PredicateKind<'tcx>>> for Predicate<'tcx> {
+    fn upcast_from(from: ty::Binder<'tcx, PredicateKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
+        tcx.mk_predicate(from)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        tcx.mk_predicate(self)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ClauseKind<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: ClauseKind<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        tcx.mk_predicate(ty::Binder::dummy(PredicateKind::Clause(from)))
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for ClauseKind<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        tcx.mk_predicate(ty::Binder::dummy(ty::PredicateKind::Clause(self)))
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, ClauseKind<'tcx>>> for Predicate<'tcx> {
+    fn upcast_from(from: ty::Binder<'tcx, ClauseKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
+        tcx.mk_predicate(from.map_bound(PredicateKind::Clause))
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, ClauseKind<'tcx>> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        tcx.mk_predicate(self.map_bound(ty::PredicateKind::Clause))
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, Clause<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: Clause<'tcx>, _tcx: TyCtxt<'tcx>) -> Self {
+        from.as_predicate()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for Clause<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.as_predicate()
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ClauseKind<'tcx>> for Clause<'tcx> {
+    fn upcast_from(from: ClauseKind<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        tcx.mk_predicate(ty::Binder::dummy(PredicateKind::Clause(from))).expect_clause()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ClauseKind<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        tcx.mk_predicate(Binder::dummy(ty::PredicateKind::Clause(self))).expect_clause()
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, ClauseKind<'tcx>>> for Clause<'tcx> {
+    fn upcast_from(from: ty::Binder<'tcx, ClauseKind<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
+        tcx.mk_predicate(from.map_bound(|clause| PredicateKind::Clause(clause))).expect_clause()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, ClauseKind<'tcx>> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        tcx.mk_predicate(self.map_bound(|clause| ty::PredicateKind::Clause(clause))).expect_clause()
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: TraitRef<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        ty::Binder::dummy(from).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for TraitRef<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        ty::Binder::dummy(self).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for TraitPredicate<'tcx> {
+    fn upcast_from(from: TraitRef<'tcx>, _tcx: TyCtxt<'tcx>) -> Self {
+        TraitPredicate { trait_ref: from, polarity: PredicatePolarity::Positive }
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, TraitPredicate<'tcx>> for TraitRef<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> TraitPredicate<'tcx> {
-        TraitPredicate { trait_ref: self, polarity: PredicatePolarity::Positive }
-    }
-}
-
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitRef<'tcx> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        let p: Predicate<'tcx> = self.to_predicate(tcx);
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitRef<'tcx>> for Clause<'tcx> {
+    fn upcast_from(from: TraitRef<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        let p: Predicate<'tcx> = from.upcast(tcx);
         p.expect_clause()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, TraitRef<'tcx>> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx);
-        pred.to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, TraitRef<'tcx>>> for Predicate<'tcx> {
+    fn upcast_from(from: ty::Binder<'tcx, TraitRef<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
+        let pred: PolyTraitPredicate<'tcx> = from.upcast(tcx);
+        pred.upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for Binder<'tcx, TraitRef<'tcx>> {
-    #[inline(always)]
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        let pred: PolyTraitPredicate<'tcx> = self.to_predicate(tcx);
-        pred.to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, TraitRef<'tcx>>> for Clause<'tcx> {
+    fn upcast_from(from: ty::Binder<'tcx, TraitRef<'tcx>>, tcx: TyCtxt<'tcx>) -> Self {
+        let pred: PolyTraitPredicate<'tcx> = from.upcast(tcx);
+        pred.upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef<'tcx>> {
-    #[inline(always)]
-    fn to_predicate(self, _: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> {
-        self.map_bound(|trait_ref| TraitPredicate {
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ty::Binder<'tcx, TraitRef<'tcx>>> for PolyTraitPredicate<'tcx> {
+    fn upcast_from(from: ty::Binder<'tcx, TraitRef<'tcx>>, _tcx: TyCtxt<'tcx>) -> Self {
+        from.map_bound(|trait_ref| TraitPredicate {
             trait_ref,
-            polarity: ty::PredicatePolarity::Positive,
+            polarity: PredicatePolarity::Positive,
         })
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        PredicateKind::Clause(ClauseKind::Trait(self)).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitPredicate<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: TraitPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        PredicateKind::Clause(ClauseKind::Trait(from)).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.map_bound(|p| PredicateKind::Clause(ClauseKind::Trait(p))).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyTraitPredicate<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: PolyTraitPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        from.map_bound(|p| PredicateKind::Clause(ClauseKind::Trait(p))).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for TraitPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        let p: Predicate<'tcx> = self.to_predicate(tcx);
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TraitPredicate<'tcx>> for Clause<'tcx> {
+    fn upcast_from(from: TraitPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        let p: Predicate<'tcx> = from.upcast(tcx);
         p.expect_clause()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyTraitPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        let p: Predicate<'tcx> = self.to_predicate(tcx);
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyTraitPredicate<'tcx>> for Clause<'tcx> {
+    fn upcast_from(from: PolyTraitPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        let p: Predicate<'tcx> = from.upcast(tcx);
         p.expect_clause()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for PolyRegionOutlivesPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyRegionOutlivesPredicate<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: PolyRegionOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        from.map_bound(|p| PredicateKind::Clause(ClauseKind::RegionOutlives(p))).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        ty::Binder::dummy(PredicateKind::Clause(ClauseKind::TypeOutlives(self))).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, TypeOutlivesPredicate<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: TypeOutlivesPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        ty::Binder::dummy(PredicateKind::Clause(ClauseKind::TypeOutlives(from))).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for ProjectionPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        ty::Binder::dummy(PredicateKind::Clause(ClauseKind::Projection(self))).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ProjectionPredicate<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: ProjectionPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        ty::Binder::dummy(PredicateKind::Clause(ClauseKind::Projection(from))).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        self.map_bound(|p| PredicateKind::Clause(ClauseKind::Projection(p))).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyProjectionPredicate<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: PolyProjectionPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        from.map_bound(|p| PredicateKind::Clause(ClauseKind::Projection(p))).upcast(tcx)
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for ProjectionPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        let p: Predicate<'tcx> = self.to_predicate(tcx);
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, ProjectionPredicate<'tcx>> for Clause<'tcx> {
+    fn upcast_from(from: ProjectionPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        let p: Predicate<'tcx> = from.upcast(tcx);
         p.expect_clause()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx, Clause<'tcx>> for PolyProjectionPredicate<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Clause<'tcx> {
-        let p: Predicate<'tcx> = self.to_predicate(tcx);
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, PolyProjectionPredicate<'tcx>> for Clause<'tcx> {
+    fn upcast_from(from: PolyProjectionPredicate<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        let p: Predicate<'tcx> = from.upcast(tcx);
         p.expect_clause()
     }
 }
 
-impl<'tcx> ToPredicate<'tcx> for NormalizesTo<'tcx> {
-    fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
-        PredicateKind::NormalizesTo(self).to_predicate(tcx)
+impl<'tcx> UpcastFrom<TyCtxt<'tcx>, NormalizesTo<'tcx>> for Predicate<'tcx> {
+    fn upcast_from(from: NormalizesTo<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
+        PredicateKind::NormalizesTo(from).upcast(tcx)
     }
 }
 
 impl<'tcx> Predicate<'tcx> {
-    pub fn to_opt_poly_trait_pred(self) -> Option<PolyTraitPredicate<'tcx>> {
+    pub fn as_trait_clause(self) -> Option<PolyTraitPredicate<'tcx>> {
         let predicate = self.kind();
         match predicate.skip_binder() {
             PredicateKind::Clause(ClauseKind::Trait(t)) => Some(predicate.rebind(t)),
@@ -1037,7 +597,7 @@
         }
     }
 
-    pub fn to_opt_poly_projection_pred(self) -> Option<PolyProjectionPredicate<'tcx>> {
+    pub fn as_projection_clause(self) -> Option<PolyProjectionPredicate<'tcx>> {
         let predicate = self.kind();
         match predicate.skip_binder() {
             PredicateKind::Clause(ClauseKind::Projection(t)) => Some(predicate.rebind(t)),
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index 9d0e112..dc77f59 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -1,6 +1,7 @@
 use crate::ty::GenericArg;
 use crate::ty::{self, Ty, TyCtxt};
 
+use hir::def::Namespace;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir as hir;
@@ -11,6 +12,8 @@
 mod pretty;
 pub use self::pretty::*;
 
+use super::Lift;
+
 pub type PrintError = std::fmt::Error;
 
 pub trait Print<'tcx, P> {
@@ -157,7 +160,7 @@
                         // If we have any generic arguments to print, we do that
                         // on top of the same path, but without its own generics.
                         _ => {
-                            if !generics.params.is_empty() && args.len() >= generics.count() {
+                            if !generics.is_own_empty() && args.len() >= generics.count() {
                                 let args = generics.own_args_no_defaults(self.tcx(), args);
                                 return self.path_generic_args(
                                     |cx| cx.print_def_path(def_id, parent_args),
@@ -334,3 +337,21 @@
         format!("module `{}`", tcx.def_path_str(def_id))
     }
 }
+
+impl<T> rustc_type_ir::ir_print::IrPrint<T> for TyCtxt<'_>
+where
+    T: Copy + for<'a, 'tcx> Lift<TyCtxt<'tcx>, Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>>,
+{
+    fn print(t: &T, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        ty::tls::with(|tcx| {
+            let mut cx = FmtPrinter::new(tcx, Namespace::TypeNS);
+            tcx.lift(*t).expect("could not lift for printing").print(&mut cx)?;
+            fmt.write_str(&cx.into_buffer())?;
+            Ok(())
+        })
+    }
+
+    fn print_debug(t: &T, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        with_no_trimmed_paths!(Self::print(t, fmt))
+    }
+}
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 5f47aef..a1ead1b 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -16,7 +16,7 @@
 use rustc_hir::def_id::{DefIdMap, DefIdSet, ModDefId, CRATE_DEF_ID, LOCAL_CRATE};
 use rustc_hir::definitions::{DefKey, DefPathDataName};
 use rustc_hir::LangItem;
-use rustc_macros::Lift;
+use rustc_macros::{extension, Lift};
 use rustc_session::cstore::{ExternCrate, ExternCrateSource};
 use rustc_session::Limit;
 use rustc_span::symbol::{kw, Ident, Symbol};
@@ -977,7 +977,7 @@
     fn pretty_print_opaque_impl_type(
         &mut self,
         def_id: DefId,
-        args: &'tcx ty::List<ty::GenericArg<'tcx>>,
+        args: ty::GenericArgsRef<'tcx>,
     ) -> Result<(), PrintError> {
         let tcx = self.tcx();
 
@@ -1277,7 +1277,7 @@
 
     fn pretty_print_inherent_projection(
         &mut self,
-        alias_ty: ty::AliasTy<'tcx>,
+        alias_ty: ty::AliasTerm<'tcx>,
     ) -> Result<(), PrintError> {
         let def_key = self.tcx().def_key(alias_ty.def_id);
         self.path_generic_args(
@@ -2860,10 +2860,9 @@
     }
 }
 
-impl<'tcx, T, U, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::OutlivesPredicate<T, U>
+impl<'tcx, T, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::OutlivesPredicate<'tcx, T>
 where
     T: Print<'tcx, P>,
-    U: Print<'tcx, P>,
 {
     fn print(&self, cx: &mut P) -> Result<(), PrintError> {
         define_scoped_cx!(cx);
@@ -2919,26 +2918,28 @@
     }
 }
 
+#[extension(pub trait PrintTraitRefExt<'tcx>)]
 impl<'tcx> ty::TraitRef<'tcx> {
-    pub fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> {
+    fn print_only_trait_path(self) -> TraitRefPrintOnlyTraitPath<'tcx> {
         TraitRefPrintOnlyTraitPath(self)
     }
 
-    pub fn print_trait_sugared(self) -> TraitRefPrintSugared<'tcx> {
+    fn print_trait_sugared(self) -> TraitRefPrintSugared<'tcx> {
         TraitRefPrintSugared(self)
     }
 
-    pub fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> {
+    fn print_only_trait_name(self) -> TraitRefPrintOnlyTraitName<'tcx> {
         TraitRefPrintOnlyTraitName(self)
     }
 }
 
+#[extension(pub trait PrintPolyTraitRefExt<'tcx>)]
 impl<'tcx> ty::Binder<'tcx, ty::TraitRef<'tcx>> {
-    pub fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> {
+    fn print_only_trait_path(self) -> ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>> {
         self.map_bound(|tr| tr.print_only_trait_path())
     }
 
-    pub fn print_trait_sugared(self) -> ty::Binder<'tcx, TraitRefPrintSugared<'tcx>> {
+    fn print_trait_sugared(self) -> ty::Binder<'tcx, TraitRefPrintSugared<'tcx>> {
         self.map_bound(|tr| tr.print_trait_sugared())
     }
 }
@@ -2952,14 +2953,16 @@
     }
 }
 
+#[extension(pub trait PrintTraitPredicateExt<'tcx>)]
 impl<'tcx> ty::TraitPredicate<'tcx> {
-    pub fn print_modifiers_and_trait_path(self) -> TraitPredPrintModifiersAndPath<'tcx> {
+    fn print_modifiers_and_trait_path(self) -> TraitPredPrintModifiersAndPath<'tcx> {
         TraitPredPrintModifiersAndPath(self)
     }
 }
 
+#[extension(pub trait PrintPolyTraitPredicateExt<'tcx>)]
 impl<'tcx> ty::PolyTraitPredicate<'tcx> {
-    pub fn print_modifiers_and_trait_path(
+    fn print_modifiers_and_trait_path(
         self,
     ) -> ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>> {
         self.map_bound(TraitPredPrintModifiersAndPath)
@@ -3012,26 +3015,62 @@
     ty::Region<'tcx>,
     Ty<'tcx>,
     &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
-    ty::Const<'tcx>,
-
-    // HACK(eddyb) these are exhaustive instead of generic,
-    // because `for<'tcx>` isn't possible yet.
-    ty::PolyExistentialProjection<'tcx>,
-    ty::PolyExistentialTraitRef<'tcx>,
-    ty::Binder<'tcx, ty::TraitRef<'tcx>>,
-    ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
-    ty::Binder<'tcx, TraitRefPrintSugared<'tcx>>,
-    ty::Binder<'tcx, ty::FnSig<'tcx>>,
-    ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
-    ty::Binder<'tcx, TraitPredPrintModifiersAndPath<'tcx>>,
-    ty::Binder<'tcx, ty::ProjectionPredicate<'tcx>>,
-    ty::OutlivesPredicate<Ty<'tcx>, ty::Region<'tcx>>,
-    ty::OutlivesPredicate<ty::Region<'tcx>, ty::Region<'tcx>>
+    ty::Const<'tcx>
 }
 
 define_print! {
     (self, cx):
 
+    ty::FnSig<'tcx> {
+        p!(write("{}", self.safety.prefix_str()));
+
+        if self.abi != Abi::Rust {
+            p!(write("extern {} ", self.abi));
+        }
+
+        p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
+    }
+
+    ty::TraitRef<'tcx> {
+        p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path()))
+    }
+
+    ty::AliasTy<'tcx> {
+        let alias_term: ty::AliasTerm<'tcx> = (*self).into();
+        p!(print(alias_term))
+    }
+
+    ty::AliasTerm<'tcx> {
+        match self.kind(cx.tcx()) {
+            ty::AliasTermKind::InherentTy => p!(pretty_print_inherent_projection(*self)),
+            ty::AliasTermKind::ProjectionTy
+            | ty::AliasTermKind::WeakTy
+            | ty::AliasTermKind::OpaqueTy
+            | ty::AliasTermKind::UnevaluatedConst
+            | ty::AliasTermKind::ProjectionConst => {
+                // If we're printing verbosely, or don't want to invoke queries
+                // (`is_impl_trait_in_trait`), then fall back to printing the def path.
+                // This is likely what you want if you're debugging the compiler anyways.
+                if !(cx.should_print_verbose() || with_reduced_queries())
+                    && cx.tcx().is_impl_trait_in_trait(self.def_id)
+                {
+                    return cx.pretty_print_opaque_impl_type(self.def_id, self.args);
+                } else {
+                    p!(print_def_path(self.def_id, self.args));
+                }
+            }
+        }
+    }
+
+    ty::TraitPredicate<'tcx> {
+        p!(print(self.trait_ref.self_ty()), ": ");
+        p!(pretty_print_bound_constness(self.trait_ref));
+        if let ty::PredicatePolarity::Negative = self.polarity {
+            p!("!");
+        }
+        p!(print(self.trait_ref.print_trait_sugared()))
+    }
+
     ty::TypeAndMut<'tcx> {
         p!(write("{}", self.mutbl.prefix_str()), print(self.ty))
     }
@@ -3072,13 +3111,15 @@
             ty::PredicateKind::AliasRelate(t1, t2, dir) => p!(print(t1), write(" {} ", dir), print(t2)),
         }
     }
-}
 
-define_print_and_forward_display! {
-    (self, cx):
-
-    &'tcx ty::List<Ty<'tcx>> {
-        p!("{{", comma_sep(self.iter()), "}}")
+    ty::ExistentialPredicate<'tcx> {
+        match *self {
+            ty::ExistentialPredicate::Trait(x) => p!(print(x)),
+            ty::ExistentialPredicate::Projection(x) => p!(print(x)),
+            ty::ExistentialPredicate::AutoTrait(def_id) => {
+                p!(print_def_path(def_id, &[]));
+            }
+        }
     }
 
     ty::ExistentialTraitRef<'tcx> {
@@ -3093,28 +3134,36 @@
         p!(write("{} = ", name), print(self.term))
     }
 
-    ty::ExistentialPredicate<'tcx> {
-        match *self {
-            ty::ExistentialPredicate::Trait(x) => p!(print(x)),
-            ty::ExistentialPredicate::Projection(x) => p!(print(x)),
-            ty::ExistentialPredicate::AutoTrait(def_id) => {
-                p!(print_def_path(def_id, &[]));
-            }
-        }
+    ty::ProjectionPredicate<'tcx> {
+        p!(print(self.projection_term), " == ");
+        cx.reset_type_limit();
+        p!(print(self.term))
     }
 
-    ty::FnSig<'tcx> {
-        p!(write("{}", self.unsafety.prefix_str()));
-
-        if self.abi != Abi::Rust {
-            p!(write("extern {} ", self.abi));
-        }
-
-        p!("fn", pretty_fn_sig(self.inputs(), self.c_variadic, self.output()));
+    ty::SubtypePredicate<'tcx> {
+        p!(print(self.a), " <: ");
+        cx.reset_type_limit();
+        p!(print(self.b))
     }
 
-    ty::TraitRef<'tcx> {
-        p!(write("<{} as {}>", self.self_ty(), self.print_only_trait_path()))
+    ty::CoercePredicate<'tcx> {
+        p!(print(self.a), " -> ");
+        cx.reset_type_limit();
+        p!(print(self.b))
+    }
+
+    ty::NormalizesTo<'tcx> {
+        p!(print(self.alias), " normalizes-to ");
+        cx.reset_type_limit();
+        p!(print(self.term))
+    }
+}
+
+define_print_and_forward_display! {
+    (self, cx):
+
+    &'tcx ty::List<Ty<'tcx>> {
+        p!("{{", comma_sep(self.iter()), "}}")
     }
 
     TraitRefPrintOnlyTraitPath<'tcx> {
@@ -3163,39 +3212,6 @@
         p!(write("{}", self.name))
     }
 
-    ty::SubtypePredicate<'tcx> {
-        p!(print(self.a), " <: ");
-        cx.reset_type_limit();
-        p!(print(self.b))
-    }
-
-    ty::CoercePredicate<'tcx> {
-        p!(print(self.a), " -> ");
-        cx.reset_type_limit();
-        p!(print(self.b))
-    }
-
-    ty::TraitPredicate<'tcx> {
-        p!(print(self.trait_ref.self_ty()), ": ");
-        p!(pretty_print_bound_constness(self.trait_ref));
-        if let ty::PredicatePolarity::Negative = self.polarity {
-            p!("!");
-        }
-        p!(print(self.trait_ref.print_trait_sugared()))
-    }
-
-    ty::ProjectionPredicate<'tcx> {
-        p!(print(self.projection_ty), " == ");
-        cx.reset_type_limit();
-        p!(print(self.term))
-    }
-
-    ty::NormalizesTo<'tcx> {
-        p!(print(self.alias), " normalizes-to ");
-        cx.reset_type_limit();
-        p!(print(self.term))
-    }
-
     ty::Term<'tcx> {
       match self.unpack() {
         ty::TermKind::Ty(ty) => p!(print(ty)),
@@ -3203,24 +3219,6 @@
       }
     }
 
-    ty::AliasTy<'tcx> {
-        if let DefKind::Impl { of_trait: false } = cx.tcx().def_kind(cx.tcx().parent(self.def_id)) {
-            p!(pretty_print_inherent_projection(*self))
-        } else {
-            // If we're printing verbosely, or don't want to invoke queries
-            // (`is_impl_trait_in_trait`), then fall back to printing the def path.
-            // This is likely what you want if you're debugging the compiler anyways.
-            if !(cx.should_print_verbose() || with_reduced_queries())
-                && cx.tcx().is_impl_trait_in_trait(self.def_id)
-            {
-                return cx.pretty_print_opaque_impl_type(self.def_id, self.args);
-            } else {
-                p!(print_def_path(self.def_id, self.args));
-            }
-
-        }
-    }
-
     ty::Predicate<'tcx> {
         p!(print(self.kind()))
     }
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index 3d9be15..d7da373 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -1,13 +1,12 @@
-use polonius_engine::Atom;
 use rustc_data_structures::intern::Interned;
 use rustc_errors::MultiSpan;
 use rustc_hir::def_id::DefId;
-use rustc_index::Idx;
 use rustc_macros::{HashStable, TyDecodable, TyEncodable};
 use rustc_span::symbol::sym;
 use rustc_span::symbol::{kw, Symbol};
 use rustc_span::{ErrorGuaranteed, DUMMY_SP};
 use rustc_type_ir::RegionKind as IrRegionKind;
+pub use rustc_type_ir::RegionVid;
 use std::ops::Deref;
 
 use crate::ty::{self, BoundVar, TyCtxt, TypeFlags};
@@ -19,7 +18,7 @@
 #[rustc_pass_by_value]
 pub struct Region<'tcx>(pub Interned<'tcx, RegionKind<'tcx>>);
 
-impl<'tcx> rustc_type_ir::IntoKind for Region<'tcx> {
+impl<'tcx> rustc_type_ir::inherent::IntoKind for Region<'tcx> {
     type Kind = RegionKind<'tcx>;
 
     fn kind(self) -> RegionKind<'tcx> {
@@ -137,7 +136,7 @@
     }
 }
 
-impl<'tcx> rustc_type_ir::new::Region<TyCtxt<'tcx>> for Region<'tcx> {
+impl<'tcx> rustc_type_ir::inherent::Region<TyCtxt<'tcx>> for Region<'tcx> {
     fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
         Region::new_bound(tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::BrAnon })
     }
@@ -348,21 +347,6 @@
     }
 }
 
-rustc_index::newtype_index! {
-    /// A **region** (lifetime) **v**ariable **ID**.
-    #[derive(HashStable)]
-    #[encodable]
-    #[orderable]
-    #[debug_format = "'?{}"]
-    pub struct RegionVid {}
-}
-
-impl Atom for RegionVid {
-    fn index(self) -> usize {
-        Idx::index(self)
-    }
-}
-
 #[derive(Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable, Copy)]
 #[derive(HashStable)]
 /// The parameter representation of late-bound function parameters, "some region
@@ -396,6 +380,16 @@
     pub kind: BoundRegionKind,
 }
 
+impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundRegion {
+    fn var(self) -> BoundVar {
+        self.var
+    }
+
+    fn assert_eq(self, var: ty::BoundVariableKind) {
+        assert_eq!(self.kind, var.expect_region())
+    }
+}
+
 impl core::fmt::Debug for BoundRegion {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self.kind {
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 7063ef0..947de3f 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -5,10 +5,11 @@
 //! subtyping, type equality, etc.
 
 use crate::ty::error::{ExpectedFound, TypeError};
-use crate::ty::{self, Expr, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable};
-use crate::ty::{GenericArg, GenericArgKind, GenericArgsRef};
+use crate::ty::{
+    self, ExistentialPredicate, ExistentialPredicateStableCmpExt as _, Expr, GenericArg,
+    GenericArgKind, GenericArgsRef, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable,
+};
 use rustc_hir as hir;
-use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_macros::TypeVisitable;
 use rustc_target::spec::abi;
@@ -145,7 +146,7 @@
         if a.c_variadic != b.c_variadic {
             return Err(TypeError::VariadicMismatch(expected_found(a.c_variadic, b.c_variadic)));
         }
-        let unsafety = relation.relate(a.unsafety, b.unsafety)?;
+        let safety = relation.relate(a.safety, b.safety)?;
         let abi = relation.relate(a.abi, b.abi)?;
 
         if a.inputs().len() != b.inputs().len() {
@@ -180,7 +181,7 @@
         Ok(ty::FnSig {
             inputs_and_output: tcx.mk_type_list_from_iter(inputs_and_output)?,
             c_variadic: a.c_variadic,
-            unsafety,
+            safety,
             abi,
         })
     }
@@ -196,13 +197,13 @@
     }
 }
 
-impl<'tcx> Relate<'tcx> for hir::Unsafety {
+impl<'tcx> Relate<'tcx> for hir::Safety {
     fn relate<R: TypeRelation<'tcx>>(
         _relation: &mut R,
-        a: hir::Unsafety,
-        b: hir::Unsafety,
-    ) -> RelateResult<'tcx, hir::Unsafety> {
-        if a != b { Err(TypeError::UnsafetyMismatch(expected_found(a, b))) } else { Ok(a) }
+        a: hir::Safety,
+        b: hir::Safety,
+    ) -> RelateResult<'tcx, hir::Safety> {
+        if a != b { Err(TypeError::SafetyMismatch(expected_found(a, b))) } else { Ok(a) }
     }
 }
 
@@ -225,8 +226,8 @@
         if a.def_id != b.def_id {
             Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id)))
         } else {
-            let args = match relation.tcx().def_kind(a.def_id) {
-                DefKind::OpaqueTy => relate_args_with_variances(
+            let args = match a.kind(relation.tcx()) {
+                ty::Opaque => relate_args_with_variances(
                     relation,
                     a.def_id,
                     relation.tcx().variances_of(a.def_id),
@@ -234,16 +235,46 @@
                     b.args,
                     false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
                 )?,
-                DefKind::AssocTy | DefKind::AssocConst | DefKind::TyAlias => {
+                ty::Projection | ty::Weak | ty::Inherent => {
                     relate_args_invariantly(relation, a.args, b.args)?
                 }
-                def => bug!("unknown alias DefKind: {def:?}"),
             };
             Ok(ty::AliasTy::new(relation.tcx(), a.def_id, args))
         }
     }
 }
 
+impl<'tcx> Relate<'tcx> for ty::AliasTerm<'tcx> {
+    fn relate<R: TypeRelation<'tcx>>(
+        relation: &mut R,
+        a: ty::AliasTerm<'tcx>,
+        b: ty::AliasTerm<'tcx>,
+    ) -> RelateResult<'tcx, ty::AliasTerm<'tcx>> {
+        if a.def_id != b.def_id {
+            Err(TypeError::ProjectionMismatched(expected_found(a.def_id, b.def_id)))
+        } else {
+            let args = match a.kind(relation.tcx()) {
+                ty::AliasTermKind::OpaqueTy => relate_args_with_variances(
+                    relation,
+                    a.def_id,
+                    relation.tcx().variances_of(a.def_id),
+                    a.args,
+                    b.args,
+                    false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle
+                )?,
+                ty::AliasTermKind::ProjectionTy
+                | ty::AliasTermKind::WeakTy
+                | ty::AliasTermKind::InherentTy
+                | ty::AliasTermKind::UnevaluatedConst
+                | ty::AliasTermKind::ProjectionConst => {
+                    relate_args_invariantly(relation, a.args, b.args)?
+                }
+            };
+            Ok(ty::AliasTerm::new(relation.tcx(), a.def_id, args))
+        }
+    }
+}
+
 impl<'tcx> Relate<'tcx> for ty::ExistentialProjection<'tcx> {
     fn relate<R: TypeRelation<'tcx>>(
         relation: &mut R,
@@ -702,14 +733,21 @@
         }
 
         let v = iter::zip(a_v, b_v).map(|(ep_a, ep_b)| {
-            use crate::ty::ExistentialPredicate::*;
             match (ep_a.skip_binder(), ep_b.skip_binder()) {
-                (Trait(a), Trait(b)) => Ok(ep_a
-                    .rebind(Trait(relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder()))),
-                (Projection(a), Projection(b)) => Ok(ep_a.rebind(Projection(
-                    relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
-                ))),
-                (AutoTrait(a), AutoTrait(b)) if a == b => Ok(ep_a.rebind(AutoTrait(a))),
+                (ExistentialPredicate::Trait(a), ExistentialPredicate::Trait(b)) => Ok(ep_a
+                    .rebind(ExistentialPredicate::Trait(
+                        relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
+                    ))),
+                (ExistentialPredicate::Projection(a), ExistentialPredicate::Projection(b)) => {
+                    Ok(ep_a.rebind(ExistentialPredicate::Projection(
+                        relation.relate(ep_a.rebind(a), ep_b.rebind(b))?.skip_binder(),
+                    )))
+                }
+                (ExistentialPredicate::AutoTrait(a), ExistentialPredicate::AutoTrait(b))
+                    if a == b =>
+                {
+                    Ok(ep_a.rebind(ExistentialPredicate::AutoTrait(a)))
+                }
                 _ => Err(TypeError::ExistentialMismatch(expected_found(a, b))),
             }
         });
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 14a77d4..af3aa3b 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -7,7 +7,7 @@
 use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
 use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
 use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
-use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
+use crate::ty::{self, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
 use rustc_ast_ir::try_visit;
 use rustc_ast_ir::visit::VisitorResult;
 use rustc_hir::def::Namespace;
@@ -55,12 +55,6 @@
     }
 }
 
-impl<'tcx> fmt::Debug for ty::ExistentialTraitRef<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        with_no_trimmed_paths!(fmt::Display::fmt(self, f))
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{:?} -> {}", self.kind, self.target)
@@ -89,55 +83,6 @@
     }
 }
 
-impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        WithInfcx::with_no_infcx(self).fmt(f)
-    }
-}
-impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::FnSig<'tcx> {
-    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
-        this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut core::fmt::Formatter<'_>,
-    ) -> core::fmt::Result {
-        let sig = this.data;
-        let ty::FnSig { inputs_and_output: _, c_variadic, unsafety, abi } = sig;
-
-        write!(f, "{}", unsafety.prefix_str())?;
-        match abi {
-            rustc_target::spec::abi::Abi::Rust => (),
-            abi => write!(f, "extern \"{abi:?}\" ")?,
-        };
-
-        write!(f, "fn(")?;
-        let inputs = sig.inputs();
-        match inputs.len() {
-            0 if *c_variadic => write!(f, "...)")?,
-            0 => write!(f, ")")?,
-            _ => {
-                for ty in &sig.inputs()[0..(sig.inputs().len() - 1)] {
-                    write!(f, "{:?}, ", &this.wrap(ty))?;
-                }
-                write!(f, "{:?}", &this.wrap(sig.inputs().last().unwrap()))?;
-                if *c_variadic {
-                    write!(f, "...")?;
-                }
-                write!(f, ")")?;
-            }
-        }
-
-        match sig.output().kind() {
-            ty::Tuple(list) if list.is_empty() => Ok(()),
-            _ => write!(f, " -> {:?}", &this.wrap(sig.output())),
-        }
-    }
-}
-
-impl<'tcx> fmt::Debug for ty::TraitRef<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        with_no_trimmed_paths!(fmt::Display::fmt(self, f))
-    }
-}
-
 impl<'tcx> ty::DebugWithInfcx<TyCtxt<'tcx>> for Ty<'tcx> {
     fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
         this: WithInfcx<'_, Infcx, &Self>,
@@ -164,25 +109,6 @@
     }
 }
 
-impl<'tcx> fmt::Debug for ty::TraitPredicate<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        // FIXME(effects) printing?
-        write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity)
-    }
-}
-
-impl<'tcx> fmt::Debug for ty::ProjectionPredicate<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_ty, self.term)
-    }
-}
-
-impl<'tcx> fmt::Debug for ty::NormalizesTo<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "NormalizesTo({:?}, {:?})", self.alias, self.term)
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{:?}", self.kind())
@@ -195,23 +121,6 @@
     }
 }
 
-impl<'tcx> fmt::Debug for AliasTy<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        WithInfcx::with_no_infcx(self).fmt(f)
-    }
-}
-impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for AliasTy<'tcx> {
-    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
-        this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut core::fmt::Formatter<'_>,
-    ) -> core::fmt::Result {
-        f.debug_struct("AliasTy")
-            .field("args", &this.map(|data| data.args))
-            .field("def_id", &this.data.def_id)
-            .finish()
-    }
-}
-
 impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for Pattern<'tcx> {
     fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
         this: WithInfcx<'_, Infcx, &Self>,
@@ -261,23 +170,6 @@
     }
 }
 
-impl<'tcx> fmt::Debug for ty::UnevaluatedConst<'tcx> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        WithInfcx::with_no_infcx(self).fmt(f)
-    }
-}
-impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::UnevaluatedConst<'tcx> {
-    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
-        this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut core::fmt::Formatter<'_>,
-    ) -> core::fmt::Result {
-        f.debug_struct("UnevaluatedConst")
-            .field("def", &this.data.def)
-            .field("args", &this.wrap(this.data.args))
-            .finish()
-    }
-}
-
 impl<'tcx> fmt::Debug for ty::Const<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         WithInfcx::with_no_infcx(self).fmt(f)
@@ -367,18 +259,6 @@
     }
 }
 
-impl<'tcx> DebugWithInfcx<TyCtxt<'tcx>> for ty::RegionVid {
-    fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
-        this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut core::fmt::Formatter<'_>,
-    ) -> core::fmt::Result {
-        match this.infcx.universe_of_lt(*this.data) {
-            Some(universe) => write!(f, "'?{}_{}", this.data.index(), universe.index()),
-            None => write!(f, "{:?}", this.data),
-        }
-    }
-}
-
 impl<'tcx, T: DebugWithInfcx<TyCtxt<'tcx>>> DebugWithInfcx<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
     fn fmt<Infcx: InferCtxtLike<Interner = TyCtxt<'tcx>>>(
         this: WithInfcx<'_, Infcx, &Self>,
@@ -441,7 +321,7 @@
     crate::ty::BoundRegionKind,
     crate::ty::AssocItem,
     crate::ty::AssocKind,
-    crate::ty::AliasKind,
+    crate::ty::AliasTyKind,
     crate::ty::Placeholder<crate::ty::BoundRegion>,
     crate::ty::Placeholder<crate::ty::BoundTy>,
     crate::ty::Placeholder<ty::BoundVar>,
@@ -463,7 +343,7 @@
 // interners).
 TrivialTypeTraversalAndLiftImpls! {
     ::rustc_hir::def_id::DefId,
-    ::rustc_hir::Unsafety,
+    ::rustc_hir::Safety,
     ::rustc_target::spec::abi::Abi,
     crate::ty::ClosureKind,
     crate::ty::ParamConst,
@@ -478,7 +358,7 @@
 ///////////////////////////////////////////////////////////////////////////
 // Lift implementations
 
-impl<'tcx, T: Lift<'tcx>> Lift<'tcx> for Option<T> {
+impl<'tcx, T: Lift<TyCtxt<'tcx>>> Lift<TyCtxt<'tcx>> for Option<T> {
     type Lifted = Option<T::Lifted>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
         Some(match self {
@@ -488,16 +368,13 @@
     }
 }
 
-impl<'a, 'tcx> Lift<'tcx> for Term<'a> {
+impl<'a, 'tcx> Lift<TyCtxt<'tcx>> for Term<'a> {
     type Lifted = ty::Term<'tcx>;
     fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
-        Some(
-            match self.unpack() {
-                TermKind::Ty(ty) => TermKind::Ty(tcx.lift(ty)?),
-                TermKind::Const(c) => TermKind::Const(tcx.lift(c)?),
-            }
-            .pack(),
-        )
+        match self.unpack() {
+            TermKind::Ty(ty) => tcx.lift(ty).map(Into::into),
+            TermKind::Const(c) => tcx.lift(c).map(Into::into),
+        }
     }
 }
 
@@ -510,38 +387,6 @@
     }
 }
 
-impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> TypeFoldable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
-    fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        folder.try_fold_binder(self)
-    }
-}
-
-impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeVisitable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
-    fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
-        visitor.visit_binder(self)
-    }
-}
-
-impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
-    fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
-        self,
-        folder: &mut F,
-    ) -> Result<Self, F::Error> {
-        self.try_map_bound(|ty| ty.try_fold_with(folder))
-    }
-}
-
-impl<'tcx, T: TypeVisitable<TyCtxt<'tcx>>> TypeSuperVisitable<TyCtxt<'tcx>>
-    for ty::Binder<'tcx, T>
-{
-    fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(&self, visitor: &mut V) -> V::Result {
-        self.as_ref().skip_binder().visit_with(visitor)
-    }
-}
-
 impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
     fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
         self,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index de70c4f..fc9a854 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -3,17 +3,16 @@
 #![allow(rustc::usage_of_ty_tykind)]
 
 use crate::infer::canonical::Canonical;
-use crate::ty::visit::ValidateBoundVars;
 use crate::ty::InferTy::*;
 use crate::ty::{
     self, AdtDef, BoundRegionKind, Discr, Region, Ty, TyCtxt, TypeFlags, TypeSuperVisitable,
-    TypeVisitable, TypeVisitableExt, TypeVisitor,
+    TypeVisitable, TypeVisitor,
 };
 use crate::ty::{GenericArg, GenericArgs, GenericArgsRef};
 use crate::ty::{List, ParamEnv};
 use hir::def::{CtorKind, DefKind};
 use rustc_data_structures::captures::Captures;
-use rustc_errors::{DiagArgValue, ErrorGuaranteed, IntoDiagArg, MultiSpan};
+use rustc_errors::{ErrorGuaranteed, MultiSpan};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::LangItem;
@@ -21,27 +20,26 @@
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
-use rustc_target::spec::abi::{self, Abi};
+use rustc_target::spec::abi;
 use std::assert_matches::debug_assert_matches;
 use std::borrow::Cow;
 use std::iter;
-use std::ops::{ControlFlow, Deref, Range};
+use std::ops::{ControlFlow, Range};
 use ty::util::IntTypeExt;
 
-use rustc_type_ir::BoundVar;
-use rustc_type_ir::CollectAndApply;
-use rustc_type_ir::DynKind;
-use rustc_type_ir::TyKind as IrTyKind;
 use rustc_type_ir::TyKind::*;
-use rustc_type_ir::TypeAndMut as IrTypeAndMut;
+use rustc_type_ir::{self as ir, BoundVar, CollectAndApply, DynKind};
 
 use super::fold::FnMutDelegate;
 use super::GenericParamDefKind;
 
 // Re-export and re-parameterize some `I = TyCtxt<'tcx>` types here
 #[rustc_diagnostic_item = "TyKind"]
-pub type TyKind<'tcx> = IrTyKind<TyCtxt<'tcx>>;
-pub type TypeAndMut<'tcx> = IrTypeAndMut<TyCtxt<'tcx>>;
+pub type TyKind<'tcx> = ir::TyKind<TyCtxt<'tcx>>;
+pub type TypeAndMut<'tcx> = ir::TypeAndMut<TyCtxt<'tcx>>;
+pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>;
+pub type FnSig<'tcx> = ir::FnSig<TyCtxt<'tcx>>;
+pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>;
 
 pub trait Article {
     fn article(&self) -> &'static str;
@@ -375,7 +373,7 @@
         self.split().signature_parts_ty
     }
 
-    pub fn coroutine_closure_sig(self) -> ty::Binder<'tcx, CoroutineClosureSignature<'tcx>> {
+    pub fn coroutine_closure_sig(self) -> Binder<'tcx, CoroutineClosureSignature<'tcx>> {
         let interior = self.coroutine_witness_ty();
         let ty::FnPtr(sig) = self.signature_parts_ty().kind() else { bug!() };
         sig.map_bound(|sig| {
@@ -390,7 +388,7 @@
                 yield_ty,
                 return_ty,
                 c_variadic: sig.c_variadic,
-                unsafety: sig.unsafety,
+                safety: sig.safety,
                 abi: sig.abi,
             }
         })
@@ -418,8 +416,8 @@
     // from scratch just for good measure.
     /// Always false
     pub c_variadic: bool,
-    /// Always [`hir::Unsafety::Normal`]
-    pub unsafety: hir::Unsafety,
+    /// Always [`hir::Safety::Safe`]
+    pub safety: hir::Safety,
     /// Always [`abi::Abi::RustCall`]
     pub abi: abi::Abi,
 }
@@ -900,372 +898,6 @@
     }
 }
 
-/// Binder is a binder for higher-ranked lifetimes or types. It is part of the
-/// compiler's representation for things like `for<'a> Fn(&'a isize)`
-/// (which would be represented by the type `PolyTraitRef ==
-/// Binder<'tcx, TraitRef>`). Note that when we instantiate,
-/// erase, or otherwise "discharge" these bound vars, we change the
-/// type from `Binder<'tcx, T>` to just `T` (see
-/// e.g., `liberate_late_bound_regions`).
-///
-/// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
-#[derive(HashStable, Lift)]
-pub struct Binder<'tcx, T> {
-    value: T,
-    bound_vars: &'tcx List<BoundVariableKind>,
-}
-
-impl<'tcx, T> Binder<'tcx, T>
-where
-    T: TypeVisitable<TyCtxt<'tcx>>,
-{
-    /// Wraps `value` in a binder, asserting that `value` does not
-    /// contain any bound vars that would be bound by the
-    /// binder. This is commonly used to 'inject' a value T into a
-    /// different binding level.
-    #[track_caller]
-    pub fn dummy(value: T) -> Binder<'tcx, T> {
-        assert!(
-            !value.has_escaping_bound_vars(),
-            "`{value:?}` has escaping bound vars, so it cannot be wrapped in a dummy binder."
-        );
-        Binder { value, bound_vars: ty::List::empty() }
-    }
-
-    pub fn bind_with_vars(value: T, bound_vars: &'tcx List<BoundVariableKind>) -> Binder<'tcx, T> {
-        if cfg!(debug_assertions) {
-            let mut validator = ValidateBoundVars::new(bound_vars);
-            value.visit_with(&mut validator);
-        }
-        Binder { value, bound_vars }
-    }
-}
-
-impl<'tcx, T> rustc_type_ir::BoundVars<TyCtxt<'tcx>> for ty::Binder<'tcx, T> {
-    fn bound_vars(&self) -> &'tcx List<ty::BoundVariableKind> {
-        self.bound_vars
-    }
-
-    fn has_no_bound_vars(&self) -> bool {
-        self.bound_vars.is_empty()
-    }
-}
-
-impl<'tcx, T> Binder<'tcx, T> {
-    /// Skips the binder and returns the "bound" value. This is a
-    /// risky thing to do because it's easy to get confused about
-    /// De Bruijn indices and the like. It is usually better to
-    /// discharge the binder using `no_bound_vars` or
-    /// `instantiate_bound_regions` or something like
-    /// that. `skip_binder` is only valid when you are either
-    /// extracting data that has nothing to do with bound vars, you
-    /// are doing some sort of test that does not involve bound
-    /// regions, or you are being very careful about your depth
-    /// accounting.
-    ///
-    /// Some examples where `skip_binder` is reasonable:
-    ///
-    /// - extracting the `DefId` from a PolyTraitRef;
-    /// - comparing the self type of a PolyTraitRef to see if it is equal to
-    ///   a type parameter `X`, since the type `X` does not reference any regions
-    pub fn skip_binder(self) -> T {
-        self.value
-    }
-
-    pub fn bound_vars(&self) -> &'tcx List<BoundVariableKind> {
-        self.bound_vars
-    }
-
-    pub fn as_ref(&self) -> Binder<'tcx, &T> {
-        Binder { value: &self.value, bound_vars: self.bound_vars }
-    }
-
-    pub fn as_deref(&self) -> Binder<'tcx, &T::Target>
-    where
-        T: Deref,
-    {
-        Binder { value: &self.value, bound_vars: self.bound_vars }
-    }
-
-    pub fn map_bound_ref_unchecked<F, U>(&self, f: F) -> Binder<'tcx, U>
-    where
-        F: FnOnce(&T) -> U,
-    {
-        let value = f(&self.value);
-        Binder { value, bound_vars: self.bound_vars }
-    }
-
-    pub fn map_bound_ref<F, U: TypeVisitable<TyCtxt<'tcx>>>(&self, f: F) -> Binder<'tcx, U>
-    where
-        F: FnOnce(&T) -> U,
-    {
-        self.as_ref().map_bound(f)
-    }
-
-    pub fn map_bound<F, U: TypeVisitable<TyCtxt<'tcx>>>(self, f: F) -> Binder<'tcx, U>
-    where
-        F: FnOnce(T) -> U,
-    {
-        let Binder { value, bound_vars } = self;
-        let value = f(value);
-        if cfg!(debug_assertions) {
-            let mut validator = ValidateBoundVars::new(bound_vars);
-            value.visit_with(&mut validator);
-        }
-        Binder { value, bound_vars }
-    }
-
-    pub fn try_map_bound<F, U: TypeVisitable<TyCtxt<'tcx>>, E>(
-        self,
-        f: F,
-    ) -> Result<Binder<'tcx, U>, E>
-    where
-        F: FnOnce(T) -> Result<U, E>,
-    {
-        let Binder { value, bound_vars } = self;
-        let value = f(value)?;
-        if cfg!(debug_assertions) {
-            let mut validator = ValidateBoundVars::new(bound_vars);
-            value.visit_with(&mut validator);
-        }
-        Ok(Binder { value, bound_vars })
-    }
-
-    /// Wraps a `value` in a binder, using the same bound variables as the
-    /// current `Binder`. This should not be used if the new value *changes*
-    /// the bound variables. Note: the (old or new) value itself does not
-    /// necessarily need to *name* all the bound variables.
-    ///
-    /// This currently doesn't do anything different than `bind`, because we
-    /// don't actually track bound vars. However, semantically, it is different
-    /// because bound vars aren't allowed to change here, whereas they are
-    /// in `bind`. This may be (debug) asserted in the future.
-    pub fn rebind<U>(&self, value: U) -> Binder<'tcx, U>
-    where
-        U: TypeVisitable<TyCtxt<'tcx>>,
-    {
-        Binder::bind_with_vars(value, self.bound_vars)
-    }
-
-    /// Unwraps and returns the value within, but only if it contains
-    /// no bound vars at all. (In other words, if this binder --
-    /// and indeed any enclosing binder -- doesn't bind anything at
-    /// all.) Otherwise, returns `None`.
-    ///
-    /// (One could imagine having a method that just unwraps a single
-    /// binder, but permits late-bound vars bound by enclosing
-    /// binders, but that would require adjusting the debruijn
-    /// indices, and given the shallow binding structure we often use,
-    /// would not be that useful.)
-    pub fn no_bound_vars(self) -> Option<T>
-    where
-        T: TypeVisitable<TyCtxt<'tcx>>,
-    {
-        // `self.value` is equivalent to `self.skip_binder()`
-        if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
-    }
-
-    /// Splits the contents into two things that share the same binder
-    /// level as the original, returning two distinct binders.
-    ///
-    /// `f` should consider bound regions at depth 1 to be free, and
-    /// anything it produces with bound regions at depth 1 will be
-    /// bound in the resulting return values.
-    pub fn split<U, V, F>(self, f: F) -> (Binder<'tcx, U>, Binder<'tcx, V>)
-    where
-        F: FnOnce(T) -> (U, V),
-    {
-        let Binder { value, bound_vars } = self;
-        let (u, v) = f(value);
-        (Binder { value: u, bound_vars }, Binder { value: v, bound_vars })
-    }
-}
-
-impl<'tcx, T> Binder<'tcx, Option<T>> {
-    pub fn transpose(self) -> Option<Binder<'tcx, T>> {
-        let Binder { value, bound_vars } = self;
-        value.map(|value| Binder { value, bound_vars })
-    }
-}
-
-impl<'tcx, T: IntoIterator> Binder<'tcx, T> {
-    pub fn iter(self) -> impl Iterator<Item = ty::Binder<'tcx, T::Item>> {
-        let Binder { value, bound_vars } = self;
-        value.into_iter().map(|value| Binder { value, bound_vars })
-    }
-}
-
-impl<'tcx, T> IntoDiagArg for Binder<'tcx, T>
-where
-    T: IntoDiagArg,
-{
-    fn into_diag_arg(self) -> DiagArgValue {
-        self.value.into_diag_arg()
-    }
-}
-
-/// Represents the projection of an associated type.
-///
-/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
-/// * For an inherent projection, this would be `Ty::N<...>`.
-/// * For an opaque type, there is no explicit syntax.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct AliasTy<'tcx> {
-    /// The parameters of the associated or opaque item.
-    ///
-    /// For a projection, these are the generic parameters for the trait and the
-    /// GAT parameters, if there are any.
-    ///
-    /// For an inherent projection, they consist of the self type and the GAT parameters,
-    /// if there are any.
-    ///
-    /// For RPIT the generic parameters are for the generics of the function,
-    /// while for TAIT it is used for the generic parameters of the alias.
-    pub args: GenericArgsRef<'tcx>,
-
-    /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
-    /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
-    /// this is an opaque.
-    ///
-    /// During codegen, `tcx.type_of(def_id)` can be used to get the type of the
-    /// underlying type if the type is an opaque.
-    ///
-    /// Note that if this is an associated type, this is not the `DefId` of the
-    /// `TraitRef` containing this associated type, which is in `tcx.associated_item(def_id).container`,
-    /// aka. `tcx.parent(def_id)`.
-    pub def_id: DefId,
-
-    /// This field exists to prevent the creation of `AliasTy` without using
-    /// [AliasTy::new].
-    _use_alias_ty_new_instead: (),
-}
-
-impl<'tcx> AliasTy<'tcx> {
-    pub fn new(
-        tcx: TyCtxt<'tcx>,
-        def_id: DefId,
-        args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
-    ) -> ty::AliasTy<'tcx> {
-        let args = tcx.check_and_mk_args(def_id, args);
-        ty::AliasTy { def_id, args, _use_alias_ty_new_instead: () }
-    }
-
-    pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasKind {
-        match tcx.def_kind(self.def_id) {
-            DefKind::AssocTy
-                if let DefKind::Impl { of_trait: false } =
-                    tcx.def_kind(tcx.parent(self.def_id)) =>
-            {
-                ty::Inherent
-            }
-            DefKind::AssocTy => ty::Projection,
-            DefKind::OpaqueTy => ty::Opaque,
-            DefKind::TyAlias => ty::Weak,
-            kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
-        }
-    }
-
-    /// Whether this alias type is an opaque.
-    pub fn is_opaque(self, tcx: TyCtxt<'tcx>) -> bool {
-        matches!(self.opt_kind(tcx), Some(ty::Opaque))
-    }
-
-    /// FIXME: rename `AliasTy` to `AliasTerm` and always handle
-    /// constants. This function can then be removed.
-    pub fn opt_kind(self, tcx: TyCtxt<'tcx>) -> Option<ty::AliasKind> {
-        match tcx.def_kind(self.def_id) {
-            DefKind::AssocTy
-                if let DefKind::Impl { of_trait: false } =
-                    tcx.def_kind(tcx.parent(self.def_id)) =>
-            {
-                Some(ty::Inherent)
-            }
-            DefKind::AssocTy => Some(ty::Projection),
-            DefKind::OpaqueTy => Some(ty::Opaque),
-            DefKind::TyAlias => Some(ty::Weak),
-            _ => None,
-        }
-    }
-
-    pub fn to_ty(self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> {
-        Ty::new_alias(tcx, self.kind(tcx), self)
-    }
-}
-
-/// The following methods work only with associated type projections.
-impl<'tcx> AliasTy<'tcx> {
-    pub fn self_ty(self) -> Ty<'tcx> {
-        self.args.type_at(0)
-    }
-
-    pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
-        AliasTy::new(tcx, self.def_id, [self_ty.into()].into_iter().chain(self.args.iter().skip(1)))
-    }
-}
-
-/// The following methods work only with trait associated type projections.
-impl<'tcx> AliasTy<'tcx> {
-    pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
-        match tcx.def_kind(self.def_id) {
-            DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
-            kind => bug!("expected a projection AliasTy; found {kind:?}"),
-        }
-    }
-
-    /// Extracts the underlying trait reference and own args from this projection.
-    /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
-    /// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own args
-    pub fn trait_ref_and_own_args(
-        self,
-        tcx: TyCtxt<'tcx>,
-    ) -> (ty::TraitRef<'tcx>, &'tcx [ty::GenericArg<'tcx>]) {
-        debug_assert!(matches!(tcx.def_kind(self.def_id), DefKind::AssocTy | DefKind::AssocConst));
-        let trait_def_id = self.trait_def_id(tcx);
-        let trait_generics = tcx.generics_of(trait_def_id);
-        (
-            ty::TraitRef::new(tcx, trait_def_id, self.args.truncate_to(tcx, trait_generics)),
-            &self.args[trait_generics.count()..],
-        )
-    }
-
-    /// Extracts the underlying trait reference from this projection.
-    /// For example, if this is a projection of `<T as Iterator>::Item`,
-    /// then this function would return a `T: Iterator` trait reference.
-    ///
-    /// WARNING: This will drop the args for generic associated types
-    /// consider calling [Self::trait_ref_and_own_args] to get those
-    /// as well.
-    pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
-        let def_id = self.trait_def_id(tcx);
-        ty::TraitRef::new(tcx, def_id, self.args.truncate_to(tcx, tcx.generics_of(def_id)))
-    }
-}
-
-/// The following methods work only with inherent associated type projections.
-impl<'tcx> AliasTy<'tcx> {
-    /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that.
-    ///
-    /// Does the following transformation:
-    ///
-    /// ```text
-    /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
-    ///
-    ///     I_i impl args
-    ///     P_j GAT args
-    /// ```
-    pub fn rebase_inherent_args_onto_impl(
-        self,
-        impl_args: ty::GenericArgsRef<'tcx>,
-        tcx: TyCtxt<'tcx>,
-    ) -> ty::GenericArgsRef<'tcx> {
-        debug_assert_eq!(self.kind(tcx), ty::Inherent);
-
-        tcx.mk_args_from_iter(impl_args.into_iter().chain(self.args.into_iter().skip(1)))
-    }
-}
-
 #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
 pub struct GenSig<'tcx> {
     pub resume_ty: Ty<'tcx>,
@@ -1273,90 +905,7 @@
     pub return_ty: Ty<'tcx>,
 }
 
-/// Signature of a function type, which we have arbitrarily
-/// decided to use to refer to the input/output types.
-///
-/// - `inputs`: is the list of arguments and their modes.
-/// - `output`: is the return type.
-/// - `c_variadic`: indicates whether this is a C-variadic function.
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
-pub struct FnSig<'tcx> {
-    pub inputs_and_output: &'tcx List<Ty<'tcx>>,
-    pub c_variadic: bool,
-    pub unsafety: hir::Unsafety,
-    pub abi: abi::Abi,
-}
-
-impl<'tcx> FnSig<'tcx> {
-    pub fn inputs(&self) -> &'tcx [Ty<'tcx>] {
-        &self.inputs_and_output[..self.inputs_and_output.len() - 1]
-    }
-
-    pub fn output(&self) -> Ty<'tcx> {
-        self.inputs_and_output[self.inputs_and_output.len() - 1]
-    }
-
-    // Creates a minimal `FnSig` to be used when encountering a `TyKind::Error` in a fallible
-    // method.
-    fn fake() -> FnSig<'tcx> {
-        FnSig {
-            inputs_and_output: List::empty(),
-            c_variadic: false,
-            unsafety: hir::Unsafety::Normal,
-            abi: abi::Abi::Rust,
-        }
-    }
-}
-
-impl<'tcx> IntoDiagArg for FnSig<'tcx> {
-    fn into_diag_arg(self) -> DiagArgValue {
-        self.to_string().into_diag_arg()
-    }
-}
-
 pub type PolyFnSig<'tcx> = Binder<'tcx, FnSig<'tcx>>;
-
-impl<'tcx> PolyFnSig<'tcx> {
-    #[inline]
-    pub fn inputs(&self) -> Binder<'tcx, &'tcx [Ty<'tcx>]> {
-        self.map_bound_ref_unchecked(|fn_sig| fn_sig.inputs())
-    }
-    #[inline]
-    #[track_caller]
-    pub fn input(&self, index: usize) -> ty::Binder<'tcx, Ty<'tcx>> {
-        self.map_bound_ref(|fn_sig| fn_sig.inputs()[index])
-    }
-    pub fn inputs_and_output(&self) -> ty::Binder<'tcx, &'tcx List<Ty<'tcx>>> {
-        self.map_bound_ref(|fn_sig| fn_sig.inputs_and_output)
-    }
-    #[inline]
-    pub fn output(&self) -> ty::Binder<'tcx, Ty<'tcx>> {
-        self.map_bound_ref(|fn_sig| fn_sig.output())
-    }
-    pub fn c_variadic(&self) -> bool {
-        self.skip_binder().c_variadic
-    }
-    pub fn unsafety(&self) -> hir::Unsafety {
-        self.skip_binder().unsafety
-    }
-    pub fn abi(&self) -> abi::Abi {
-        self.skip_binder().abi
-    }
-
-    pub fn is_fn_trait_compatible(&self) -> bool {
-        matches!(
-            self.skip_binder(),
-            ty::FnSig {
-                unsafety: rustc_hir::Unsafety::Normal,
-                abi: Abi::Rust,
-                c_variadic: false,
-                ..
-            }
-        )
-    }
-}
-
 pub type CanonicalPolyFnSig<'tcx> = Canonical<'tcx, Binder<'tcx, FnSig<'tcx>>>;
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
@@ -1411,6 +960,16 @@
     pub kind: BoundTyKind,
 }
 
+impl<'tcx> rustc_type_ir::inherent::BoundVarLike<TyCtxt<'tcx>> for BoundTy {
+    fn var(self) -> BoundVar {
+        self.var
+    }
+
+    fn assert_eq(self, var: ty::BoundVariableKind) {
+        assert_eq!(self.kind, var.expect_ty())
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)]
 #[derive(HashStable)]
 pub enum BoundTyKind {
@@ -1511,7 +1070,7 @@
     #[inline]
     pub fn new_alias(
         tcx: TyCtxt<'tcx>,
-        kind: ty::AliasKind,
+        kind: ty::AliasTyKind,
         alias_ty: ty::AliasTy<'tcx>,
     ) -> Ty<'tcx> {
         debug_assert_matches!(
@@ -1812,10 +1371,30 @@
     }
 }
 
-impl<'tcx> rustc_type_ir::new::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
+impl<'tcx> rustc_type_ir::inherent::Ty<TyCtxt<'tcx>> for Ty<'tcx> {
+    fn new_bool(tcx: TyCtxt<'tcx>) -> Self {
+        tcx.types.bool
+    }
+
+    fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferTy) -> Self {
+        Ty::new_infer(tcx, infer)
+    }
+
+    fn new_var(tcx: TyCtxt<'tcx>, vid: ty::TyVid) -> Self {
+        Ty::new_var(tcx, vid)
+    }
+
     fn new_anon_bound(tcx: TyCtxt<'tcx>, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self {
         Ty::new_bound(tcx, debruijn, ty::BoundTy { var, kind: ty::BoundTyKind::Anon })
     }
+
+    fn new_alias(
+        interner: TyCtxt<'tcx>,
+        kind: ty::AliasTyKind,
+        alias_ty: ty::AliasTy<'tcx>,
+    ) -> Self {
+        Ty::new_alias(interner, kind, alias_ty)
+    }
 }
 
 /// Type utilities
@@ -2164,13 +1743,11 @@
     ///
     /// The parameter `explicit` indicates if this is an *explicit* dereference.
     /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly.
-    pub fn builtin_deref(self, explicit: bool) -> Option<TypeAndMut<'tcx>> {
-        match self.kind() {
-            Adt(def, _) if def.is_box() => {
-                Some(TypeAndMut { ty: self.boxed_ty(), mutbl: hir::Mutability::Not })
-            }
-            Ref(_, ty, mutbl) => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }),
-            RawPtr(ty, mutbl) if explicit => Some(TypeAndMut { ty: *ty, mutbl: *mutbl }),
+    pub fn builtin_deref(self, explicit: bool) -> Option<Ty<'tcx>> {
+        match *self.kind() {
+            Adt(def, _) if def.is_box() => Some(self.boxed_ty()),
+            Ref(_, ty, _) => Some(ty),
+            RawPtr(ty, _) if explicit => Some(ty),
             _ => None,
         }
     }
@@ -2189,7 +1766,12 @@
             FnPtr(f) => *f,
             Error(_) => {
                 // ignore errors (#54954)
-                ty::Binder::dummy(FnSig::fake())
+                Binder::dummy(ty::FnSig {
+                    inputs_and_output: ty::List::empty(),
+                    c_variadic: false,
+                    safety: hir::Safety::Safe,
+                    abi: abi::Abi::Rust,
+                })
             }
             Closure(..) => bug!(
                 "to get the signature of a closure, use `args.as_closure().sig()` not `fn_sig()`",
@@ -2782,6 +2364,13 @@
     }
 }
 
+impl<'tcx> rustc_type_ir::inherent::Tys<TyCtxt<'tcx>> for &'tcx ty::List<Ty<'tcx>> {
+    fn split_inputs_and_output(self) -> (&'tcx [Ty<'tcx>], Ty<'tcx>) {
+        let (output, inputs) = self.split_last().unwrap();
+        (inputs, *output)
+    }
+}
+
 /// Extra information about why we ended up with a particular variance.
 /// This is only used to add more information to error messages, and
 /// has no effect on soundness. While choosing the 'wrong' `VarianceDiagInfo`
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index cf5decf..cf1cbb9 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -15,7 +15,7 @@
 pub struct TraitDef {
     pub def_id: DefId,
 
-    pub unsafety: hir::Unsafety,
+    pub safety: hir::Safety,
 
     /// If `true`, then this trait had the `#[rustc_paren_sugar]`
     /// attribute, indicating that it should be used with `Foo()`
@@ -39,11 +39,16 @@
     /// also have already switched to the new trait solver.
     pub is_coinductive: bool,
 
-    /// If `true`, then this trait has the `#[rustc_skip_array_during_method_dispatch]`
+    /// If `true`, then this trait has the `#[rustc_skip_during_method_dispatch(array)]`
     /// attribute, indicating that editions before 2021 should not consider this trait
     /// during method dispatch if the receiver is an array.
     pub skip_array_during_method_dispatch: bool,
 
+    /// If `true`, then this trait has the `#[rustc_skip_during_method_dispatch(boxed_slice)]`
+    /// attribute, indicating that editions before 2024 should not consider this trait
+    /// during method dispatch if the receiver is a boxed slice.
+    pub skip_boxed_slice_during_method_dispatch: bool,
+
     /// Used to determine whether the standard library is allowed to specialize
     /// on this trait.
     pub specialization_kind: TraitSpecializationKind,
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 41f417d..24e3e62 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -79,6 +79,10 @@
     /// Stores the actual binding mode for all instances of [`BindingMode`].
     pat_binding_modes: ItemLocalMap<BindingMode>,
 
+    /// Top-level patterns whose match ergonomics need to be desugared
+    /// by the Rust 2021 -> 2024 migration lint.
+    rust_2024_migration_desugared_pats: ItemLocalSet,
+
     /// Stores the types which were implicitly dereferenced in pattern binding modes
     /// for later usage in THIR lowering. For example,
     ///
@@ -229,6 +233,7 @@
             adjustments: Default::default(),
             pat_binding_modes: Default::default(),
             pat_adjustments: Default::default(),
+            rust_2024_migration_desugared_pats: Default::default(),
             skipped_ref_pats: Default::default(),
             closure_kind_origins: Default::default(),
             liberated_fn_sigs: Default::default(),
@@ -432,6 +437,20 @@
         LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
     }
 
+    pub fn rust_2024_migration_desugared_pats(&self) -> LocalSetInContext<'_> {
+        LocalSetInContext {
+            hir_owner: self.hir_owner,
+            data: &self.rust_2024_migration_desugared_pats,
+        }
+    }
+
+    pub fn rust_2024_migration_desugared_pats_mut(&mut self) -> LocalSetInContextMut<'_> {
+        LocalSetInContextMut {
+            hir_owner: self.hir_owner,
+            data: &mut self.rust_2024_migration_desugared_pats,
+        }
+    }
+
     pub fn skipped_ref_pats(&self) -> LocalSetInContext<'_> {
         LocalSetInContext { hir_owner: self.hir_owner, data: &self.skipped_ref_pats }
     }
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index f5e973f..8c14f1e 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -2,10 +2,10 @@
 
 use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use crate::query::{IntoQueryParam, Providers};
-use crate::ty::layout::IntegerExt;
+use crate::ty::layout::{FloatExt, IntegerExt};
 use crate::ty::{
-    self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitableExt,
+    self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt, Upcast,
 };
 use crate::ty::{GenericArgKind, GenericArgsRef};
 use rustc_apfloat::Float as _;
@@ -20,7 +20,7 @@
 use rustc_macros::{extension, HashStable, TyDecodable, TyEncodable};
 use rustc_session::Limit;
 use rustc_span::sym;
-use rustc_target::abi::{Integer, IntegerType, Primitive, Size};
+use rustc_target::abi::{Float, Integer, IntegerType, Size};
 use rustc_target::spec::abi::Abi;
 use smallvec::{smallvec, SmallVec};
 use std::{fmt, iter};
@@ -1086,7 +1086,7 @@
         {
             p.kind()
                 .rebind(ty::ProjectionPredicate {
-                    projection_ty: projection_pred.projection_ty.fold_with(self),
+                    projection_term: projection_pred.projection_term.fold_with(self),
                     // Don't fold the term on the RHS of the projection predicate.
                     // This is because for default trait methods with RPITITs, we
                     // install a `NormalizesTo(Projection(RPITIT) -> Opaque(RPITIT))`
@@ -1094,7 +1094,7 @@
                     // anything that requires `ParamEnv::with_reveal_all_normalized`.
                     term: projection_pred.term,
                 })
-                .to_predicate(self.tcx)
+                .upcast(self.tcx)
         } else {
             p.super_fold_with(self)
         }
@@ -1130,7 +1130,7 @@
     }
 
     fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
-        if !ct.ty().has_type_flags(ty::TypeFlags::HAS_TY_WEAK) {
+        if !ct.has_type_flags(ty::TypeFlags::HAS_TY_WEAK) {
             return ct;
         }
         ct.super_fold_with(self)
@@ -1145,8 +1145,7 @@
             ty::Char => Size::from_bytes(4),
             ty::Int(ity) => Integer::from_int_ty(&tcx, ity).size(),
             ty::Uint(uty) => Integer::from_uint_ty(&tcx, uty).size(),
-            ty::Float(ty::FloatTy::F32) => Primitive::F32.size(&tcx),
-            ty::Float(ty::FloatTy::F64) => Primitive::F64.size(&tcx),
+            ty::Float(fty) => Float::from_float_ty(fty).size(),
             _ => bug!("non primitive type"),
         }
     }
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 218567b..b1bbfd4 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -1,7 +1,6 @@
 use crate::ty::{self, Binder, Ty, TyCtxt, TypeFlags};
 
 use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::sso::SsoHashSet;
 use rustc_type_ir::fold::TypeFoldable;
 use std::ops::ControlFlow;
 
@@ -145,103 +144,6 @@
     }
 }
 
-pub struct ValidateBoundVars<'tcx> {
-    bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
-    binder_index: ty::DebruijnIndex,
-    // We may encounter the same variable at different levels of binding, so
-    // this can't just be `Ty`
-    visited: SsoHashSet<(ty::DebruijnIndex, Ty<'tcx>)>,
-}
-
-impl<'tcx> ValidateBoundVars<'tcx> {
-    pub fn new(bound_vars: &'tcx ty::List<ty::BoundVariableKind>) -> Self {
-        ValidateBoundVars {
-            bound_vars,
-            binder_index: ty::INNERMOST,
-            visited: SsoHashSet::default(),
-        }
-    }
-}
-
-impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ValidateBoundVars<'tcx> {
-    type Result = ControlFlow<()>;
-
-    fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
-        &mut self,
-        t: &Binder<'tcx, T>,
-    ) -> Self::Result {
-        self.binder_index.shift_in(1);
-        let result = t.super_visit_with(self);
-        self.binder_index.shift_out(1);
-        result
-    }
-
-    fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
-        if t.outer_exclusive_binder() < self.binder_index
-            || !self.visited.insert((self.binder_index, t))
-        {
-            return ControlFlow::Break(());
-        }
-        match *t.kind() {
-            ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
-                if self.bound_vars.len() <= bound_ty.var.as_usize() {
-                    bug!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars);
-                }
-                let list_var = self.bound_vars[bound_ty.var.as_usize()];
-                match list_var {
-                    ty::BoundVariableKind::Ty(kind) => {
-                        if kind != bound_ty.kind {
-                            bug!(
-                                "Mismatched type kinds: {:?} doesn't var in list {:?}",
-                                bound_ty.kind,
-                                list_var
-                            );
-                        }
-                    }
-                    _ => {
-                        bug!("Mismatched bound variable kinds! Expected type, found {:?}", list_var)
-                    }
-                }
-            }
-
-            _ => (),
-        };
-
-        t.super_visit_with(self)
-    }
-
-    fn visit_region(&mut self, r: ty::Region<'tcx>) -> Self::Result {
-        match *r {
-            ty::ReBound(index, br) if index == self.binder_index => {
-                if self.bound_vars.len() <= br.var.as_usize() {
-                    bug!("Not enough bound vars: {:?} not found in {:?}", br, self.bound_vars);
-                }
-                let list_var = self.bound_vars[br.var.as_usize()];
-                match list_var {
-                    ty::BoundVariableKind::Region(kind) => {
-                        if kind != br.kind {
-                            bug!(
-                                "Mismatched region kinds: {:?} doesn't match var ({:?}) in list ({:?})",
-                                br.kind,
-                                list_var,
-                                self.bound_vars
-                            );
-                        }
-                    }
-                    _ => bug!(
-                        "Mismatched bound variable kinds! Expected region, found {:?}",
-                        list_var
-                    ),
-                }
-            }
-
-            _ => (),
-        };
-
-        ControlFlow::Continue(())
-    }
-}
-
 /// Collects all the late-bound regions at the innermost binding level
 /// into a hash set.
 struct LateBoundRegionsCollector {
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 5c17c0b..79f36cf 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -65,7 +65,7 @@
             std::iter::repeat(err).take(arity),
             err,
             false,
-            rustc_hir::Unsafety::Normal,
+            rustc_hir::Safety::Safe,
             rustc_target::spec::abi::Abi::Rust,
         ));
 
@@ -141,7 +141,7 @@
             && frame.query.dep_kind == dep_kinds::variances_of
             && let Some(def_id) = frame.query.def_id
         {
-            let n = tcx.generics_of(def_id).params.len();
+            let n = tcx.generics_of(def_id).own_params.len();
             vec![ty::Variance::Bivariant; n].leak()
         } else {
             span_bug!(
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml
index 6618e4f..77f2723 100644
--- a/compiler/rustc_mir_build/Cargo.toml
+++ b/compiler/rustc_mir_build/Cargo.toml
@@ -16,6 +16,7 @@
 rustc_hir = { path = "../rustc_hir" }
 rustc_index = { path = "../rustc_index" }
 rustc_infer = { path = "../rustc_infer" }
+rustc_lint = { path = "../rustc_lint" }
 rustc_macros = { path = "../rustc_macros" }
 rustc_middle = { path = "../rustc_middle" }
 rustc_pattern_analysis = { path = "../rustc_pattern_analysis" }
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index 34440c6..0bb44db 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -267,6 +267,8 @@
 
 mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
 
+mir_build_rust_2024_incompatible_pat = the semantics of this pattern will 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
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 00e99f3..6ae98e1 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -1,6 +1,7 @@
 use crate::build::ForGuard::OutsideGuard;
 use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
 use rustc_middle::middle::region::Scope;
+use rustc_middle::span_bug;
 use rustc_middle::thir::*;
 use rustc_middle::{mir::*, ty};
 use rustc_span::Span;
diff --git a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs
index 566dba4..9cfb25e 100644
--- a/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs
+++ b/compiler/rustc_mir_build/src/build/coverageinfo/mcdc.rs
@@ -1,5 +1,6 @@
 use std::collections::VecDeque;
 
+use rustc_middle::bug;
 use rustc_middle::mir::coverage::{
     BlockMarkerId, ConditionId, ConditionInfo, MCDCBranchSpan, MCDCDecisionSpan,
 };
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index 30877e3..a0a512a 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -24,6 +24,7 @@
 use rustc_index::{IndexSlice, IndexVec};
 use rustc_middle::{
     mir::*,
+    span_bug,
     thir::*,
     ty::{ParamEnv, Ty, TyCtxt},
 };
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index c669d3f..6f8cfc3 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -195,9 +195,15 @@
             },
             @call(mir_checked, args) => {
                 parse_by_kind!(self, args[0], _, "binary op",
-                    ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp(
-                        *op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))
-                    )),
+                    ExprKind::Binary { op, lhs, rhs } => {
+                        if let Some(op_with_overflow) = op.wrapping_to_overflowing() {
+                            Ok(Rvalue::BinaryOp(
+                                op_with_overflow, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))
+                            ))
+                        } else {
+                            Err(self.expr_error(expr_id, "No WithOverflow form of this operator"))
+                        }
+                    },
                 )
             },
             @call(mir_offset, args) => {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index a557f61..817f5f7 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -9,6 +9,7 @@
 use rustc_middle::ty::{
     self, CanonicalUserType, CanonicalUserTypeAnnotation, TyCtxt, UserTypeAnnotationIndex,
 };
+use rustc_middle::{bug, span_bug};
 use rustc_target::abi::Size;
 
 impl<'a, 'tcx> Builder<'a, 'tcx> {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index 060b328..9963629 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -4,6 +4,7 @@
 use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
 use crate::build::{BlockAnd, BlockAndExtension, Builder, Capture, CaptureMap};
 use rustc_hir::def_id::LocalDefId;
+use rustc_middle::bug;
 use rustc_middle::hir::place::Projection as HirProjection;
 use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
 use rustc_middle::middle::region;
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 260ab05..60a2827 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -9,6 +9,7 @@
 use crate::build::expr::category::{Category, RvalueFunc};
 use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary};
 use rustc_hir::lang_items::LangItem;
+use rustc_middle::bug;
 use rustc_middle::middle::region;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::*;
@@ -567,11 +568,13 @@
                 let result_tup = Ty::new_tup(self.tcx, &[ty, bool_ty]);
                 let result_value = self.temp(result_tup, span);
 
+                let op_with_overflow = op.wrapping_to_overflowing().unwrap();
+
                 self.cfg.push_assign(
                     block,
                     source_info,
                     result_value,
-                    Rvalue::CheckedBinaryOp(op, Box::new((lhs.to_copy(), rhs.to_copy()))),
+                    Rvalue::BinaryOp(op_with_overflow, Box::new((lhs.to_copy(), rhs.to_copy()))),
                 );
                 let val_fld = FieldIdx::ZERO;
                 let of_fld = FieldIdx::new(1);
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index c8360b6..f8c9107 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -7,6 +7,7 @@
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir as hir;
 use rustc_middle::mir::*;
+use rustc_middle::span_bug;
 use rustc_middle::thir::*;
 use rustc_middle::ty::CanonicalUserTypeAnnotation;
 use rustc_span::source_map::Spanned;
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 7cf4fac..3fc7193 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -12,6 +12,7 @@
 use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode};
 use rustc_data_structures::{fx::FxIndexMap, stack::ensure_sufficient_stack};
 use rustc_hir::{BindingMode, ByRef};
+use rustc_middle::bug;
 use rustc_middle::middle::region;
 use rustc_middle::mir::{self, *};
 use rustc_middle::thir::{self, *};
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 7f65697..f3faeb4 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -13,6 +13,7 @@
 use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::GenericArg;
 use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use rustc_span::source_map::Spanned;
 use rustc_span::symbol::{sym, Symbol};
diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs
index 02bea6f..14c74c7 100644
--- a/compiler/rustc_mir_build/src/build/matches/util.rs
+++ b/compiler/rustc_mir_build/src/build/matches/util.rs
@@ -2,7 +2,6 @@
 use crate::build::matches::{Binding, Candidate, FlatPat, MatchPair, TestCase};
 use crate::build::Builder;
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_middle::mir::*;
 use rustc_middle::thir::{self, *};
 use rustc_middle::ty::TypeVisitableExt;
@@ -180,9 +179,7 @@
                         cx.tcx,
                         ty::InlineConstArgsParts {
                             parent_args: ty::GenericArgs::identity_for_item(cx.tcx, parent_id),
-                            ty: cx
-                                .infcx
-                                .next_ty_var(TypeVariableOrigin { param_def_id: None, span }),
+                            ty: cx.infcx.next_ty_var(span),
                         },
                     )
                     .args;
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index 794e7eb..92cd7f7 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -20,6 +20,7 @@
 use rustc_middle::query::TyCtxtAt;
 use rustc_middle::thir::{self, ExprId, LintLevel, LocalVarId, Param, ParamId, PatKind, Thir};
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::sym;
 use rustc_span::Span;
 use rustc_span::Symbol;
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 2d31e84..be32363 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -90,6 +90,7 @@
 use rustc_middle::middle::region;
 use rustc_middle::mir::*;
 use rustc_middle::thir::{ExprId, LintLevel};
+use rustc_middle::{bug, span_bug};
 use rustc_session::lint::Level;
 use rustc_span::source_map::Spanned;
 use rustc_span::{Span, DUMMY_SP};
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 227d19c..b5f7ffb 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -4,6 +4,7 @@
 use rustc_errors::DiagArgValue;
 use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability};
 use rustc_middle::mir::BorrowKind;
+use rustc_middle::span_bug;
 use rustc_middle::thir::visit::Visitor;
 use rustc_middle::thir::*;
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -390,7 +391,7 @@
                 return; // don't visit the whole expression
             }
             ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
-                if self.thir[fun].ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe {
+                if self.thir[fun].ty.fn_sig(self.tcx).safety() == hir::Safety::Unsafe {
                     let func_id = if let ty::FnDef(func_id, _) = self.thir[fun].ty.kind() {
                         Some(*func_id)
                     } else {
@@ -920,7 +921,7 @@
 
     let hir_id = tcx.local_def_id_to_hir_id(def);
     let safety_context = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
-        if fn_sig.header.unsafety == hir::Unsafety::Unsafe {
+        if fn_sig.header.safety == hir::Safety::Unsafe {
             SafetyContext::UnsafeFn
         } else {
             SafetyContext::Safe
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index f67113a..e2a2846 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -950,3 +950,30 @@
     #[note(mir_build_missing_box)]
     MissingBox,
 }
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_rust_2024_incompatible_pat)]
+pub struct Rust2024IncompatiblePat {
+    #[subdiagnostic]
+    pub sugg: Rust2024IncompatiblePatSugg,
+}
+
+pub struct Rust2024IncompatiblePatSugg {
+    pub suggestion: Vec<(Span, String)>,
+}
+
+impl Subdiagnostic for Rust2024IncompatiblePatSugg {
+    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
+        self,
+        diag: &mut Diag<'_, G>,
+        _f: &F,
+    ) {
+        let applicability =
+            if self.suggestion.iter().all(|(span, _)| span.can_be_used_for_suggestions()) {
+                Applicability::MachineApplicable
+            } else {
+                Applicability::MaybeIncorrect
+            };
+        diag.multipart_suggestion("desugar the match ergonomics", self.suggestion, applicability);
+    }
+}
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index e79e3b8..2e1cb0e 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -12,8 +12,6 @@
 
 #[macro_use]
 extern crate tracing;
-#[macro_use]
-extern crate rustc_middle;
 
 mod build;
 mod check_unsafety;
diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs
index 65cc132..03c7c1f 100644
--- a/compiler/rustc_mir_build/src/thir/constant.rs
+++ b/compiler/rustc_mir_build/src/thir/constant.rs
@@ -1,4 +1,5 @@
 use rustc_ast as ast;
+use rustc_middle::bug;
 use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
 use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt};
 
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index c697e16..b776666 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -21,6 +21,7 @@
 use rustc_middle::ty::{
     self, AdtKind, InlineConstArgs, InlineConstArgsParts, ScalarInt, Ty, UpvarArgs, UserType,
 };
+use rustc_middle::{bug, span_bug};
 use rustc_span::source_map::Spanned;
 use rustc_span::{sym, Span, DUMMY_SP};
 use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 79738b5..d1d21f8 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -13,6 +13,7 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::HirId;
 use rustc_hir::Node;
+use rustc_middle::bug;
 use rustc_middle::middle::region;
 use rustc_middle::thir::*;
 use rustc_middle::ty::{self, RvalueScopes, TyCtxt};
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 25ab904..592f0dc 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -1,9 +1,3 @@
-use rustc_pattern_analysis::errors::Uncovered;
-use rustc_pattern_analysis::rustc::{
-    Constructor, DeconstructedPat, MatchArm, RustcPatCtxt as PatCtxt, Usefulness, UsefulnessReport,
-    WitnessPat,
-};
-
 use crate::errors::*;
 
 use rustc_arena::{DroplessArena, TypedArena};
@@ -14,11 +8,17 @@
 use rustc_hir::def::*;
 use rustc_hir::def_id::LocalDefId;
 use rustc_hir::{self as hir, BindingMode, ByRef, HirId};
+use rustc_middle::bug;
 use rustc_middle::middle::limits::get_limit_size;
 use rustc_middle::thir::visit::Visitor;
 use rustc_middle::thir::*;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
+use rustc_pattern_analysis::errors::Uncovered;
+use rustc_pattern_analysis::rustc::{
+    Constructor, DeconstructedPat, MatchArm, RustcPatCtxt as PatCtxt, Usefulness, UsefulnessReport,
+    WitnessPat,
+};
 use rustc_session::lint::builtin::{
     BINDINGS_WITH_VARIANT_NAME, IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS,
 };
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 65c53be..c6f81c3 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -4,6 +4,7 @@
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::Obligation;
 use rustc_middle::mir;
+use rustc_middle::span_bug;
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
 use rustc_middle::ty::{self, Ty, TyCtxt, ValTree};
 use rustc_session::lint;
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 5c01668..dc845b3 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -11,8 +11,9 @@
 use rustc_errors::codes::*;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
-use rustc_hir::{self as hir, RangeEnd};
+use rustc_hir::{self as hir, ByRef, Mutability, RangeEnd};
 use rustc_index::Idx;
+use rustc_lint as lint;
 use rustc_middle::mir::interpret::{ErrorHandled, GlobalId, LitToConstError, LitToConstInput};
 use rustc_middle::mir::{self, Const};
 use rustc_middle::thir::{
@@ -20,6 +21,7 @@
 };
 use rustc_middle::ty::layout::IntegerExt;
 use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{ErrorGuaranteed, Span};
 use rustc_target::abi::{FieldIdx, Integer};
@@ -30,6 +32,9 @@
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     typeck_results: &'a ty::TypeckResults<'tcx>,
+
+    /// Used by the Rust 2024 migration lint.
+    rust_2024_migration_suggestion: Option<Rust2024IncompatiblePatSugg>,
 }
 
 pub(super) fn pat_from_hir<'a, 'tcx>(
@@ -38,9 +43,25 @@
     typeck_results: &'a ty::TypeckResults<'tcx>,
     pat: &'tcx hir::Pat<'tcx>,
 ) -> Box<Pat<'tcx>> {
-    let mut pcx = PatCtxt { tcx, param_env, typeck_results };
+    let mut pcx = PatCtxt {
+        tcx,
+        param_env,
+        typeck_results,
+        rust_2024_migration_suggestion: typeck_results
+            .rust_2024_migration_desugared_pats()
+            .contains(pat.hir_id)
+            .then_some(Rust2024IncompatiblePatSugg { suggestion: Vec::new() }),
+    };
     let result = pcx.lower_pattern(pat);
     debug!("pat_from_hir({:?}) = {:?}", pat, result);
+    if let Some(sugg) = pcx.rust_2024_migration_suggestion {
+        tcx.emit_node_span_lint(
+            lint::builtin::RUST_2024_INCOMPATIBLE_PAT,
+            pat.hir_id,
+            pat.span,
+            Rust2024IncompatiblePat { sugg },
+        );
+    }
     result
 }
 
@@ -73,17 +94,38 @@
             }
             _ => self.lower_pattern_unadjusted(pat),
         };
-        self.typeck_results.pat_adjustments().get(pat.hir_id).unwrap_or(&vec![]).iter().rev().fold(
-            unadjusted_pat,
-            |pat: Box<_>, ref_ty| {
-                debug!("{:?}: wrapping pattern with type {:?}", pat, ref_ty);
-                Box::new(Pat {
-                    span: pat.span,
-                    ty: *ref_ty,
-                    kind: PatKind::Deref { subpattern: pat },
+
+        let adjustments: &[Ty<'tcx>] =
+            self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
+        let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, ref_ty| {
+            debug!("{:?}: wrapping pattern with type {:?}", thir_pat, ref_ty);
+            Box::new(Pat {
+                span: thir_pat.span,
+                ty: *ref_ty,
+                kind: PatKind::Deref { subpattern: thir_pat },
+            })
+        });
+
+        if let Some(s) = &mut self.rust_2024_migration_suggestion
+            && !adjustments.is_empty()
+        {
+            let suggestion_str: String = adjustments
+                .iter()
+                .map(|ref_ty| {
+                    let &ty::Ref(_, _, mutbl) = ref_ty.kind() else {
+                        span_bug!(pat.span, "pattern implicitly dereferences a non-ref type");
+                    };
+
+                    match mutbl {
+                        ty::Mutability::Not => "&",
+                        ty::Mutability::Mut => "&mut ",
+                    }
                 })
-            },
-        )
+                .collect();
+            s.suggestion.push((pat.span.shrink_to_lo(), suggestion_str));
+        };
+
+        adjusted_pat
     }
 
     fn lower_pattern_range_endpoint(
@@ -272,7 +314,7 @@
                 PatKind::Deref { subpattern: self.lower_pattern(subpattern) }
             }
 
-            hir::PatKind::Slice(prefix, ref slice, suffix) => {
+            hir::PatKind::Slice(prefix, slice, suffix) => {
                 self.slice_or_array_pattern(pat.span, ty, prefix, slice, suffix)
             }
 
@@ -284,7 +326,7 @@
                 PatKind::Leaf { subpatterns }
             }
 
-            hir::PatKind::Binding(_, id, ident, ref sub) => {
+            hir::PatKind::Binding(explicit_ba, id, ident, sub) => {
                 if let Some(ident_span) = ident.span.find_ancestor_inside(span) {
                     span = span.with_hi(ident_span.hi());
                 }
@@ -295,6 +337,20 @@
                     .get(pat.hir_id)
                     .expect("missing binding mode");
 
+                if let Some(s) = &mut self.rust_2024_migration_suggestion
+                    && explicit_ba.0 == ByRef::No
+                    && let ByRef::Yes(mutbl) = mode.0
+                {
+                    let sugg_str = match mutbl {
+                        Mutability::Not => "ref ",
+                        Mutability::Mut => "ref mut ",
+                    };
+                    s.suggestion.push((
+                        pat.span.with_lo(ident.span.lo()).shrink_to_lo(),
+                        sugg_str.to_owned(),
+                    ))
+                }
+
                 // A ref x pattern is the same node used for x, and as such it has
                 // x's type, which is &T, where we want T (the type being matched).
                 let var_ty = ty;
@@ -366,10 +422,7 @@
         pats.iter().map(|p| self.lower_pattern(p)).collect()
     }
 
-    fn lower_opt_pattern(
-        &mut self,
-        pat: &'tcx Option<&'tcx hir::Pat<'tcx>>,
-    ) -> Option<Box<Pat<'tcx>>> {
+    fn lower_opt_pattern(&mut self, pat: Option<&'tcx hir::Pat<'tcx>>) -> Option<Box<Pat<'tcx>>> {
         pat.map(|p| self.lower_pattern(p))
     }
 
@@ -378,7 +431,7 @@
         span: Span,
         ty: Ty<'tcx>,
         prefix: &'tcx [hir::Pat<'tcx>],
-        slice: &'tcx Option<&'tcx hir::Pat<'tcx>>,
+        slice: Option<&'tcx hir::Pat<'tcx>>,
         suffix: &'tcx [hir::Pat<'tcx>],
     ) -> PatKind<'tcx> {
         let prefix = self.lower_patterns(prefix);
diff --git a/compiler/rustc_mir_build/src/thir/util.rs b/compiler/rustc_mir_build/src/thir/util.rs
index 52c9cf1..340eb3c 100644
--- a/compiler/rustc_mir_build/src/thir/util.rs
+++ b/compiler/rustc_mir_build/src/thir/util.rs
@@ -1,4 +1,5 @@
 use rustc_hir as hir;
+use rustc_middle::bug;
 use rustc_middle::ty::{self, CanonicalUserType, TyCtxt, UserType};
 
 pub(crate) trait UserAnnotatedTyHelpers<'tcx> {
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index bdc70de..706bb79 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -109,7 +109,6 @@
             | Rvalue::Repeat(..)
             | Rvalue::Len(..)
             | Rvalue::BinaryOp(..)
-            | Rvalue::CheckedBinaryOp(..)
             | Rvalue::NullaryOp(..)
             | Rvalue::UnaryOp(..)
             | Rvalue::Discriminant(..)
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 6ae7df7..521ecb1 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -420,8 +420,7 @@
             | Rvalue::Cast(_, ref operand, _)
             | Rvalue::ShallowInitBox(ref operand, _)
             | Rvalue::UnaryOp(_, ref operand) => self.gather_operand(operand),
-            Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs))
-            | Rvalue::CheckedBinaryOp(ref _binop, box (ref lhs, ref rhs)) => {
+            Rvalue::BinaryOp(ref _binop, box (ref lhs, ref rhs)) => {
                 self.gather_operand(lhs);
                 self.gather_operand(rhs);
             }
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 807bef0..1e5322d 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -184,7 +184,6 @@
             | Rvalue::Len(..)
             | Rvalue::Cast(..)
             | Rvalue::BinaryOp(..)
-            | Rvalue::CheckedBinaryOp(..)
             | Rvalue::NullaryOp(..)
             | Rvalue::UnaryOp(..)
             | Rvalue::Discriminant(..)
diff --git a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
index ba70a44..d43fca3 100644
--- a/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
+++ b/compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
@@ -1,5 +1,6 @@
 use rustc_ast::InlineAsmOptions;
 use rustc_middle::mir::*;
+use rustc_middle::span_bug;
 use rustc_middle::ty::layout;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_target::spec::abi::Abi;
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index 0af8872..5199c41 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -106,7 +106,7 @@
         }
 
         let pointee_ty =
-            pointer_ty.builtin_deref(true).expect("no builtin_deref for an unsafe pointer").ty;
+            pointer_ty.builtin_deref(true).expect("no builtin_deref for an unsafe pointer");
         // Ideally we'd support this in the future, but for now we are limited to sized types.
         if !pointee_ty.is_sized(self.tcx, self.param_env) {
             debug!("Unsafe pointer, but pointee is not known to be sized: {:?}", pointer_ty);
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index a405ed6..5f67bd7 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -1,5 +1,6 @@
 use rustc_middle::mir::visit::{PlaceContext, Visitor};
 use rustc_middle::mir::*;
+use rustc_middle::span_bug;
 use rustc_middle::ty::{self, TyCtxt};
 
 use crate::MirLint;
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 3008016..a3e6e5a 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -70,6 +70,7 @@
 use rustc_middle::ty::CoroutineArgs;
 use rustc_middle::ty::InstanceDef;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_mir_dataflow::impls::{
     MaybeBorrowedLocals, MaybeLiveLocals, MaybeRequiresStorage, MaybeStorageLive,
 };
diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
index 3d6c1a9..10c0567 100644
--- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
+++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
@@ -71,6 +71,7 @@
 
 use rustc_data_structures::unord::UnordMap;
 use rustc_hir as hir;
+use rustc_middle::bug;
 use rustc_middle::hir::place::{Projection, ProjectionKind};
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::{self, dump_mir, MirPass};
diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs
index 6e73a47..b596851 100644
--- a/compiler/rustc_mir_transform/src/coverage/counters.rs
+++ b/compiler/rustc_mir_transform/src/coverage/counters.rs
@@ -4,13 +4,14 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::graph::DirectedGraph;
 use rustc_index::IndexVec;
+use rustc_middle::bug;
 use rustc_middle::mir::coverage::{CounterId, CovTerm, Expression, ExpressionId, Op};
 
 use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverageGraphWithLoops};
 
 /// The coverage counter or counter expression associated with a particular
 /// BCB node or BCB edge.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub(super) enum BcbCounter {
     Counter { id: CounterId },
     Expression { id: ExpressionId },
@@ -34,6 +35,13 @@
     }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+struct BcbExpression {
+    lhs: BcbCounter,
+    op: Op,
+    rhs: BcbCounter,
+}
+
 #[derive(Debug)]
 pub(super) enum CounterIncrementSite {
     Node { bcb: BasicCoverageBlock },
@@ -55,9 +63,13 @@
     /// We currently don't iterate over this map, but if we do in the future,
     /// switch it back to `FxIndexMap` to avoid query stability hazards.
     bcb_edge_counters: FxHashMap<(BasicCoverageBlock, BasicCoverageBlock), BcbCounter>,
+
     /// Table of expression data, associating each expression ID with its
     /// corresponding operator (+ or -) and its LHS/RHS operands.
-    expressions: IndexVec<ExpressionId, Expression>,
+    expressions: IndexVec<ExpressionId, BcbExpression>,
+    /// Remember expressions that have already been created (or simplified),
+    /// so that we don't create unnecessary duplicates.
+    expressions_memo: FxHashMap<BcbExpression, BcbCounter>,
 }
 
 impl CoverageCounters {
@@ -75,6 +87,7 @@
             bcb_counters: IndexVec::from_elem_n(None, num_bcbs),
             bcb_edge_counters: FxHashMap::default(),
             expressions: IndexVec::new(),
+            expressions_memo: FxHashMap::default(),
         };
 
         MakeBcbCounters::new(&mut this, basic_coverage_blocks)
@@ -89,8 +102,57 @@
     }
 
     fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter {
-        let expression = Expression { lhs: lhs.as_term(), op, rhs: rhs.as_term() };
-        let id = self.expressions.push(expression);
+        let new_expr = BcbExpression { lhs, op, rhs };
+        *self
+            .expressions_memo
+            .entry(new_expr)
+            .or_insert_with(|| Self::make_expression_inner(&mut self.expressions, new_expr))
+    }
+
+    /// This is an associated function so that we can call it while borrowing
+    /// `&mut self.expressions_memo`.
+    fn make_expression_inner(
+        expressions: &mut IndexVec<ExpressionId, BcbExpression>,
+        new_expr: BcbExpression,
+    ) -> BcbCounter {
+        // Simplify expressions using basic algebra.
+        //
+        // Some of these cases might not actually occur in practice, depending
+        // on the details of how the instrumentor builds expressions.
+        let BcbExpression { lhs, op, rhs } = new_expr;
+
+        if let BcbCounter::Expression { id } = lhs {
+            let lhs_expr = &expressions[id];
+
+            // Simplify `(a - b) + b` to `a`.
+            if lhs_expr.op == Op::Subtract && op == Op::Add && lhs_expr.rhs == rhs {
+                return lhs_expr.lhs;
+            }
+            // Simplify `(a + b) - b` to `a`.
+            if lhs_expr.op == Op::Add && op == Op::Subtract && lhs_expr.rhs == rhs {
+                return lhs_expr.lhs;
+            }
+            // Simplify `(a + b) - a` to `b`.
+            if lhs_expr.op == Op::Add && op == Op::Subtract && lhs_expr.lhs == rhs {
+                return lhs_expr.rhs;
+            }
+        }
+
+        if let BcbCounter::Expression { id } = rhs {
+            let rhs_expr = &expressions[id];
+
+            // Simplify `a + (b - a)` to `b`.
+            if op == Op::Add && rhs_expr.op == Op::Subtract && lhs == rhs_expr.rhs {
+                return rhs_expr.lhs;
+            }
+            // Simplify `a - (a - b)` to `b`.
+            if op == Op::Subtract && rhs_expr.op == Op::Subtract && lhs == rhs_expr.lhs {
+                return rhs_expr.rhs;
+            }
+        }
+
+        // Simplification failed, so actually create the new expression.
+        let id = expressions.push(new_expr);
         BcbCounter::Expression { id }
     }
 
@@ -165,7 +227,21 @@
     }
 
     pub(super) fn into_expressions(self) -> IndexVec<ExpressionId, Expression> {
-        self.expressions
+        let old_len = self.expressions.len();
+        let expressions = self
+            .expressions
+            .into_iter()
+            .map(|BcbExpression { lhs, op, rhs }| Expression {
+                lhs: lhs.as_term(),
+                op,
+                rhs: rhs.as_term(),
+            })
+            .collect::<IndexVec<ExpressionId, _>>();
+
+        // Expression IDs are indexes into this vector, so make sure we didn't
+        // accidentally invalidate them by changing its length.
+        assert_eq!(old_len, expressions.len());
+        expressions
     }
 }
 
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 1895735..fd74a2a 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -4,6 +4,7 @@
 use rustc_data_structures::graph::{self, DirectedGraph, StartNode};
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
+use rustc_middle::bug;
 use rustc_middle::mir::{self, BasicBlock, Terminator, TerminatorKind};
 
 use std::cmp::Ordering;
diff --git a/compiler/rustc_mir_transform/src/coverage/mappings.rs b/compiler/rustc_mir_transform/src/coverage/mappings.rs
index ddbe133..61aabea 100644
--- a/compiler/rustc_mir_transform/src/coverage/mappings.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mappings.rs
@@ -52,104 +52,104 @@
     pub(super) decision_depth: u16,
 }
 
-pub(super) struct CoverageSpans {
-    bcb_has_mappings: BitSet<BasicCoverageBlock>,
+#[derive(Default)]
+pub(super) struct ExtractedMappings {
     pub(super) code_mappings: Vec<CodeMapping>,
     pub(super) branch_pairs: Vec<BranchPair>,
-    test_vector_bitmap_bytes: u32,
+    pub(super) mcdc_bitmap_bytes: u32,
     pub(super) mcdc_branches: Vec<MCDCBranch>,
     pub(super) mcdc_decisions: Vec<MCDCDecision>,
 }
 
-impl CoverageSpans {
-    pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool {
-        self.bcb_has_mappings.contains(bcb)
-    }
-
-    pub(super) fn test_vector_bitmap_bytes(&self) -> u32 {
-        self.test_vector_bitmap_bytes
-    }
-}
-
 /// Extracts coverage-relevant spans from MIR, and associates them with
 /// their corresponding BCBs.
-///
-/// Returns `None` if no coverage-relevant spans could be extracted.
-pub(super) fn generate_coverage_spans(
+pub(super) fn extract_all_mapping_info_from_mir(
     mir_body: &mir::Body<'_>,
     hir_info: &ExtractedHirInfo,
     basic_coverage_blocks: &CoverageGraph,
-) -> Option<CoverageSpans> {
-    let mut code_mappings = vec![];
-    let mut branch_pairs = vec![];
-    let mut mcdc_branches = vec![];
-    let mut mcdc_decisions = vec![];
-
+) -> ExtractedMappings {
     if hir_info.is_async_fn {
         // An async function desugars into a function that returns a future,
         // with the user code wrapped in a closure. Any spans in the desugared
         // outer function will be unhelpful, so just keep the signature span
         // and ignore all of the spans in the MIR body.
+        let mut mappings = ExtractedMappings::default();
         if let Some(span) = hir_info.fn_sig_span_extended {
-            code_mappings.push(CodeMapping { span, bcb: START_BCB });
+            mappings.code_mappings.push(CodeMapping { span, bcb: START_BCB });
         }
-    } else {
-        extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings);
-
-        branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks));
-
-        extract_mcdc_mappings(
-            mir_body,
-            hir_info.body_span,
-            basic_coverage_blocks,
-            &mut mcdc_branches,
-            &mut mcdc_decisions,
-        );
+        return mappings;
     }
 
-    if code_mappings.is_empty()
-        && branch_pairs.is_empty()
-        && mcdc_branches.is_empty()
-        && mcdc_decisions.is_empty()
-    {
-        return None;
-    }
+    let mut code_mappings = vec![];
+    let mut branch_pairs = vec![];
+    let mut mcdc_bitmap_bytes = 0;
+    let mut mcdc_branches = vec![];
+    let mut mcdc_decisions = vec![];
 
-    // Identify which BCBs have one or more mappings.
-    let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes());
-    let mut insert = |bcb| {
-        bcb_has_mappings.insert(bcb);
-    };
+    extract_refined_covspans(mir_body, hir_info, basic_coverage_blocks, &mut code_mappings);
 
-    for &CodeMapping { span: _, bcb } in &code_mappings {
-        insert(bcb);
-    }
-    for &BranchPair { true_bcb, false_bcb, .. } in &branch_pairs {
-        insert(true_bcb);
-        insert(false_bcb);
-    }
-    for &MCDCBranch { true_bcb, false_bcb, .. } in &mcdc_branches {
-        insert(true_bcb);
-        insert(false_bcb);
-    }
+    branch_pairs.extend(extract_branch_pairs(mir_body, hir_info, basic_coverage_blocks));
 
-    // Determine the length of the test vector bitmap.
-    let test_vector_bitmap_bytes = mcdc_decisions
-        .iter()
-        .map(|&MCDCDecision { bitmap_idx, conditions_num, .. }| {
-            bitmap_idx + (1_u32 << u32::from(conditions_num)).div_ceil(8)
-        })
-        .max()
-        .unwrap_or(0);
+    extract_mcdc_mappings(
+        mir_body,
+        hir_info.body_span,
+        basic_coverage_blocks,
+        &mut mcdc_bitmap_bytes,
+        &mut mcdc_branches,
+        &mut mcdc_decisions,
+    );
 
-    Some(CoverageSpans {
-        bcb_has_mappings,
+    ExtractedMappings {
         code_mappings,
         branch_pairs,
-        test_vector_bitmap_bytes,
+        mcdc_bitmap_bytes,
         mcdc_branches,
         mcdc_decisions,
-    })
+    }
+}
+
+impl ExtractedMappings {
+    pub(super) fn all_bcbs_with_counter_mappings(
+        &self,
+        basic_coverage_blocks: &CoverageGraph, // Only used for allocating a correctly-sized set
+    ) -> BitSet<BasicCoverageBlock> {
+        // Fully destructure self to make sure we don't miss any fields that have mappings.
+        let Self {
+            code_mappings,
+            branch_pairs,
+            mcdc_bitmap_bytes: _,
+            mcdc_branches,
+            mcdc_decisions,
+        } = self;
+
+        // Identify which BCBs have one or more mappings.
+        let mut bcbs_with_counter_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes());
+        let mut insert = |bcb| {
+            bcbs_with_counter_mappings.insert(bcb);
+        };
+
+        for &CodeMapping { span: _, bcb } in code_mappings {
+            insert(bcb);
+        }
+        for &BranchPair { true_bcb, false_bcb, .. } in branch_pairs {
+            insert(true_bcb);
+            insert(false_bcb);
+        }
+        for &MCDCBranch { true_bcb, false_bcb, .. } in mcdc_branches {
+            insert(true_bcb);
+            insert(false_bcb);
+        }
+
+        // MC/DC decisions refer to BCBs, but don't require those BCBs to have counters.
+        if bcbs_with_counter_mappings.is_empty() {
+            debug_assert!(
+                mcdc_decisions.is_empty(),
+                "A function with no counter mappings shouldn't have any decisions: {mcdc_decisions:?}",
+            );
+        }
+
+        bcbs_with_counter_mappings
+    }
 }
 
 fn resolve_block_markers(
@@ -215,6 +215,7 @@
     mir_body: &mir::Body<'_>,
     body_span: Span,
     basic_coverage_blocks: &CoverageGraph,
+    mcdc_bitmap_bytes: &mut u32,
     mcdc_branches: &mut impl Extend<MCDCBranch>,
     mcdc_decisions: &mut impl Extend<MCDCDecision>,
 ) {
@@ -253,8 +254,6 @@
         },
     ));
 
-    let mut next_bitmap_idx = 0;
-
     mcdc_decisions.extend(branch_info.mcdc_decision_spans.iter().filter_map(
         |decision: &mir::coverage::MCDCDecisionSpan| {
             let (span, _) = unexpand_into_body_span_with_visible_macro(decision.span, body_span)?;
@@ -265,8 +264,11 @@
                 .map(|&marker| bcb_from_marker(marker))
                 .collect::<Option<_>>()?;
 
-            let bitmap_idx = next_bitmap_idx;
-            next_bitmap_idx += (1_u32 << decision.conditions_num).div_ceil(8);
+            // Each decision containing N conditions needs 2^N bits of space in
+            // the bitmap, rounded up to a whole number of bytes.
+            // The decision's "bitmap index" points to its first byte in the bitmap.
+            let bitmap_idx = *mcdc_bitmap_bytes;
+            *mcdc_bitmap_bytes += (1_u32 << decision.conditions_num).div_ceil(8);
 
             Some(MCDCDecision {
                 span,
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 1e2599e..28e0c63 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -7,13 +7,9 @@
 #[cfg(test)]
 mod tests;
 
-use self::counters::{CounterIncrementSite, CoverageCounters};
-use self::graph::{BasicCoverageBlock, CoverageGraph};
-use self::mappings::CoverageSpans;
-
-use crate::MirPass;
-
-use rustc_middle::mir::coverage::*;
+use rustc_middle::mir::coverage::{
+    CodeRegion, CoverageKind, DecisionInfo, FunctionCoverageInfo, Mapping, MappingKind,
+};
 use rustc_middle::mir::{
     self, BasicBlock, BasicBlockData, SourceInfo, Statement, StatementKind, Terminator,
     TerminatorKind,
@@ -23,6 +19,11 @@
 use rustc_span::source_map::SourceMap;
 use rustc_span::{BytePos, Pos, RelativeBytePos, Span, Symbol};
 
+use crate::coverage::counters::{CounterIncrementSite, CoverageCounters};
+use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph};
+use crate::coverage::mappings::ExtractedMappings;
+use crate::MirPass;
+
 /// Inserts `StatementKind::Coverage` statements that either instrument the binary with injected
 /// counters, via intrinsic `llvm.instrprof.increment`, and/or inject metadata used during codegen
 /// to construct the coverage map.
@@ -69,24 +70,27 @@
     let basic_coverage_blocks = CoverageGraph::from_mir(mir_body);
 
     ////////////////////////////////////////////////////
-    // Compute coverage spans from the `CoverageGraph`.
-    let Some(coverage_spans) =
-        mappings::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks)
-    else {
-        // No relevant spans were found in MIR, so skip instrumenting this function.
-        return;
-    };
+    // Extract coverage spans and other mapping info from MIR.
+    let extracted_mappings =
+        mappings::extract_all_mapping_info_from_mir(mir_body, &hir_info, &basic_coverage_blocks);
 
     ////////////////////////////////////////////////////
     // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure
     // every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock`
     // and all `Expression` dependencies (operands) are also generated, for any other
     // `BasicCoverageBlock`s not already associated with a coverage span.
-    let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb);
-    let coverage_counters =
-        CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans);
+    let bcbs_with_counter_mappings =
+        extracted_mappings.all_bcbs_with_counter_mappings(&basic_coverage_blocks);
+    if bcbs_with_counter_mappings.is_empty() {
+        // No relevant spans were found in MIR, so skip instrumenting this function.
+        return;
+    }
 
-    let mappings = create_mappings(tcx, &hir_info, &coverage_spans, &coverage_counters);
+    let bcb_has_counter_mappings = |bcb| bcbs_with_counter_mappings.contains(bcb);
+    let coverage_counters =
+        CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_counter_mappings);
+
+    let mappings = create_mappings(tcx, &hir_info, &extracted_mappings, &coverage_counters);
     if mappings.is_empty() {
         // No spans could be converted into valid mappings, so skip this function.
         debug!("no spans could be converted into valid mappings; skipping");
@@ -96,13 +100,13 @@
     inject_coverage_statements(
         mir_body,
         &basic_coverage_blocks,
-        bcb_has_coverage_spans,
+        bcb_has_counter_mappings,
         &coverage_counters,
     );
 
-    inject_mcdc_statements(mir_body, &basic_coverage_blocks, &coverage_spans);
+    inject_mcdc_statements(mir_body, &basic_coverage_blocks, &extracted_mappings);
 
-    let mcdc_num_condition_bitmaps = coverage_spans
+    let mcdc_num_condition_bitmaps = extracted_mappings
         .mcdc_decisions
         .iter()
         .map(|&mappings::MCDCDecision { decision_depth, .. }| decision_depth)
@@ -112,7 +116,7 @@
     mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo {
         function_source_hash: hir_info.function_source_hash,
         num_counters: coverage_counters.num_counters(),
-        mcdc_bitmap_bytes: coverage_spans.test_vector_bitmap_bytes(),
+        mcdc_bitmap_bytes: extracted_mappings.mcdc_bitmap_bytes,
         expressions: coverage_counters.into_expressions(),
         mappings,
         mcdc_num_condition_bitmaps,
@@ -127,7 +131,7 @@
 fn create_mappings<'tcx>(
     tcx: TyCtxt<'tcx>,
     hir_info: &ExtractedHirInfo,
-    coverage_spans: &CoverageSpans,
+    extracted_mappings: &ExtractedMappings,
     coverage_counters: &CoverageCounters,
 ) -> Vec<Mapping> {
     let source_map = tcx.sess.source_map();
@@ -148,9 +152,18 @@
     };
     let region_for_span = |span: Span| make_code_region(source_map, file_name, span, body_span);
 
+    // Fully destructure the mappings struct to make sure we don't miss any kinds.
+    let ExtractedMappings {
+        code_mappings,
+        branch_pairs,
+        mcdc_bitmap_bytes: _,
+        mcdc_branches,
+        mcdc_decisions,
+    } = extracted_mappings;
     let mut mappings = Vec::new();
 
-    mappings.extend(coverage_spans.code_mappings.iter().filter_map(
+    mappings.extend(code_mappings.iter().filter_map(
+        // Ordinary code mappings are the simplest kind.
         |&mappings::CodeMapping { span, bcb }| {
             let code_region = region_for_span(span)?;
             let kind = MappingKind::Code(term_for_bcb(bcb));
@@ -158,7 +171,7 @@
         },
     ));
 
-    mappings.extend(coverage_spans.branch_pairs.iter().filter_map(
+    mappings.extend(branch_pairs.iter().filter_map(
         |&mappings::BranchPair { span, true_bcb, false_bcb }| {
             let true_term = term_for_bcb(true_bcb);
             let false_term = term_for_bcb(false_bcb);
@@ -168,7 +181,7 @@
         },
     ));
 
-    mappings.extend(coverage_spans.mcdc_branches.iter().filter_map(
+    mappings.extend(mcdc_branches.iter().filter_map(
         |&mappings::MCDCBranch { span, true_bcb, false_bcb, condition_info, decision_depth: _ }| {
             let code_region = region_for_span(span)?;
             let true_term = term_for_bcb(true_bcb);
@@ -181,7 +194,7 @@
         },
     ));
 
-    mappings.extend(coverage_spans.mcdc_decisions.iter().filter_map(
+    mappings.extend(mcdc_decisions.iter().filter_map(
         |&mappings::MCDCDecision { span, bitmap_idx, conditions_num, .. }| {
             let code_region = region_for_span(span)?;
             let kind = MappingKind::MCDCDecision(DecisionInfo { bitmap_idx, conditions_num });
@@ -249,12 +262,8 @@
 fn inject_mcdc_statements<'tcx>(
     mir_body: &mut mir::Body<'tcx>,
     basic_coverage_blocks: &CoverageGraph,
-    coverage_spans: &CoverageSpans,
+    extracted_mappings: &ExtractedMappings,
 ) {
-    if coverage_spans.test_vector_bitmap_bytes() == 0 {
-        return;
-    }
-
     // Inject test vector update first because `inject_statement` always insert new statement at head.
     for &mappings::MCDCDecision {
         span: _,
@@ -262,7 +271,7 @@
         bitmap_idx,
         conditions_num: _,
         decision_depth,
-    } in &coverage_spans.mcdc_decisions
+    } in &extracted_mappings.mcdc_decisions
     {
         for end in end_bcbs {
             let end_bb = basic_coverage_blocks[*end].leader_bb();
@@ -275,7 +284,7 @@
     }
 
     for &mappings::MCDCBranch { span: _, true_bcb, false_bcb, condition_info, decision_depth } in
-        &coverage_spans.mcdc_branches
+        &extracted_mappings.mcdc_branches
     {
         let Some(condition_info) = condition_info else { continue };
         let id = condition_info.condition_id;
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index f77ee63..6571525 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -61,17 +61,7 @@
         .max()
         .unwrap_or(CounterId::ZERO);
 
-    let mcdc_bitmap_bytes = mir_body
-        .coverage_branch_info
-        .as_deref()
-        .map(|info| {
-            info.mcdc_decision_spans
-                .iter()
-                .fold(0, |acc, decision| acc + (1_u32 << decision.conditions_num).div_ceil(8))
-        })
-        .unwrap_or_default();
-
-    CoverageIdsInfo { max_counter_id, mcdc_bitmap_bytes }
+    CoverageIdsInfo { max_counter_id }
 }
 
 fn all_coverage_in_mir_body<'a, 'tcx>(
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index a0570c4..f2f76ac 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -1,3 +1,4 @@
+use rustc_middle::bug;
 use rustc_middle::mir;
 use rustc_span::{BytePos, Span};
 
diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
index 4ce37b5..d1727a9 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs
@@ -1,5 +1,6 @@
 use rustc_data_structures::captures::Captures;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_middle::bug;
 use rustc_middle::mir::coverage::CoverageKind;
 use rustc_middle::mir::{
     self, AggregateKind, FakeReadCause, Rvalue, Statement, StatementKind, Terminator,
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index cf1a2b3..ca64688 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -30,6 +30,7 @@
 use itertools::Itertools;
 use rustc_data_structures::graph::{DirectedGraph, Successors};
 use rustc_index::{Idx, IndexVec};
+use rustc_middle::bug;
 use rustc_middle::mir::*;
 use rustc_middle::ty;
 use rustc_span::{BytePos, Pos, Span, DUMMY_SP};
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index d0f6ec8..3d24a56 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -6,6 +6,7 @@
 use rustc_const_eval::interpret::{ImmTy, Immediate, InterpCx, OpTy, PlaceTy, Projectable};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::def::DefKind;
+use rustc_middle::bug;
 use rustc_middle::mir::interpret::{InterpResult, Scalar};
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::*;
@@ -164,7 +165,9 @@
                     }
                 }
             }
-            Rvalue::CheckedBinaryOp(op, box (left, right)) => {
+            Rvalue::BinaryOp(overflowing_op, box (left, right))
+                if let Some(op) = overflowing_op.overflowing_to_wrapping() =>
+            {
                 // Flood everything now, so we can use `insert_value_idx` directly later.
                 state.flood(target.as_ref(), self.map());
 
@@ -174,7 +177,7 @@
                 let overflow_target = self.map().apply(target, TrackElem::Field(1_u32.into()));
 
                 if value_target.is_some() || overflow_target.is_some() {
-                    let (val, overflow) = self.binary_op(state, *op, left, right);
+                    let (val, overflow) = self.binary_op(state, op, left, right);
 
                     if let Some(value_target) = value_target {
                         // We have flooded `target` earlier.
@@ -202,7 +205,7 @@
                 if let Some(target_len) = self.map().find_len(target.as_ref())
                     && let operand_ty = operand.ty(self.local_decls, self.tcx)
                     && let Some(operand_ty) = operand_ty.builtin_deref(true)
-                    && let ty::Array(_, len) = operand_ty.ty.kind()
+                    && let ty::Array(_, len) = operand_ty.kind()
                     && let Some(len) = Const::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env)
                 {
                     state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map());
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index e6317e5..08dba1d 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -13,6 +13,7 @@
 //!
 
 use crate::util::is_within_packed;
+use rustc_middle::bug;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 10fea09..b1016c0 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -135,6 +135,7 @@
 use rustc_data_structures::fx::{FxIndexMap, IndexEntry, IndexOccupiedEntry};
 use rustc_index::bit_set::BitSet;
 use rustc_index::interval::SparseIntervalMatrix;
+use rustc_middle::bug;
 use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
 use rustc_middle::mir::HasLocalDecls;
 use rustc_middle::mir::{dump_mir, PassWhere};
@@ -563,7 +564,7 @@
                     | Rvalue::ShallowInitBox(op, _) => {
                         self.add_operand(op);
                     }
-                    Rvalue::BinaryOp(_, ops) | Rvalue::CheckedBinaryOp(_, ops) => {
+                    Rvalue::BinaryOp(_, ops) => {
                         for op in [&ops.0, &ops.1] {
                             self.add_operand(op);
                         }
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index 318674f..d955b96 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -6,6 +6,7 @@
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::visit::MutVisitor;
 use rustc_middle::mir::*;
+use rustc_middle::span_bug;
 use rustc_middle::ty::{Ty, TyCtxt};
 use rustc_target::abi::FieldIdx;
 
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index 0970c4d..5e3cd85 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -4,6 +4,7 @@
 use rustc_middle::query::Providers;
 use rustc_middle::ty::layout;
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_session::lint::builtin::FFI_UNWIND_CALLS;
 use rustc_target::spec::abi::Abi;
 use rustc_target::spec::PanicStrategy;
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index 30b1ca6..434529c 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -158,7 +158,7 @@
             .lint_root;
         // FIXME: use existing printing routines to print the function signature
         let fn_sig = self.tcx.fn_sig(fn_id).instantiate(self.tcx, fn_args);
-        let unsafety = fn_sig.unsafety().prefix_str();
+        let unsafety = fn_sig.safety().prefix_str();
         let abi = match fn_sig.abi() {
             Abi::Rust => String::from(""),
             other_abi => {
diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 4dd595c..1f3e407 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -91,6 +91,7 @@
 use rustc_index::bit_set::BitSet;
 use rustc_index::newtype_index;
 use rustc_index::IndexVec;
+use rustc_middle::bug;
 use rustc_middle::mir::interpret::GlobalAlloc;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
@@ -594,7 +595,7 @@
                 let ty = place.ty(self.local_decls, self.tcx).ty;
                 if let Some(Mutability::Not) = ty.ref_mutability()
                     && let Some(pointee_ty) = ty.builtin_deref(true)
-                    && pointee_ty.ty.is_freeze(self.tcx, self.param_env)
+                    && pointee_ty.is_freeze(self.tcx, self.param_env)
                 {
                     // An immutable borrow `_x` always points to the same value for the
                     // lifetime of the borrow, so we can merge all instances of `*_x`.
@@ -830,23 +831,18 @@
                 // on both operands for side effect.
                 let lhs = lhs?;
                 let rhs = rhs?;
-                if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) {
-                    return Some(value);
+
+                if let Some(op) = op.overflowing_to_wrapping() {
+                    if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) {
+                        return Some(value);
+                    }
+                    Value::CheckedBinaryOp(op, lhs, rhs)
+                } else {
+                    if let Some(value) = self.simplify_binary(op, false, ty, lhs, rhs) {
+                        return Some(value);
+                    }
+                    Value::BinaryOp(op, lhs, rhs)
                 }
-                Value::BinaryOp(op, lhs, rhs)
-            }
-            Rvalue::CheckedBinaryOp(op, box (ref mut lhs, ref mut rhs)) => {
-                let ty = lhs.ty(self.local_decls, self.tcx);
-                let lhs = self.simplify_operand(lhs, location);
-                let rhs = self.simplify_operand(rhs, location);
-                // Only short-circuit options after we called `simplify_operand`
-                // on both operands for side effect.
-                let lhs = lhs?;
-                let rhs = rhs?;
-                if let Some(value) = self.simplify_binary(op, true, ty, lhs, rhs) {
-                    return Some(value);
-                }
-                Value::CheckedBinaryOp(op, lhs, rhs)
             }
             Rvalue::UnaryOp(op, ref mut arg) => {
                 let arg = self.simplify_operand(arg, location)?;
@@ -1133,9 +1129,9 @@
         if let Value::Cast { kind, from, to, .. } = self.get(inner)
             && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize) = kind
             && let Some(from) = from.builtin_deref(true)
-            && let ty::Array(_, len) = from.ty.kind()
+            && let ty::Array(_, len) = from.kind()
             && let Some(to) = to.builtin_deref(true)
-            && let ty::Slice(..) = to.ty.kind()
+            && let ty::Slice(..) = to.kind()
         {
             return self.insert_constant(Const::from_ty_const(*len, self.tcx));
         }
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index 7a3b08f..401056c 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -6,6 +6,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::BitSet;
 use rustc_index::Idx;
+use rustc_middle::bug;
 use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index fd768cc..f1adeab 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -2,6 +2,7 @@
 
 use crate::simplify::simplify_duplicate_switch_targets;
 use rustc_ast::attr;
+use rustc_middle::bug;
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout;
 use rustc_middle::ty::layout::ValidityRequirement;
diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs
index a458297..ae80765 100644
--- a/compiler/rustc_mir_transform/src/jump_threading.rs
+++ b/compiler/rustc_mir_transform/src/jump_threading.rs
@@ -41,6 +41,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
+use rustc_middle::bug;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::visit::Visitor;
 use rustc_middle::mir::*;
diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs
index 90c1c7b..38fc37a 100644
--- a/compiler/rustc_mir_transform/src/known_panics_lint.rs
+++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs
@@ -14,6 +14,7 @@
 use rustc_hir::def::DefKind;
 use rustc_hir::HirId;
 use rustc_index::{bit_set::BitSet, IndexVec};
+use rustc_middle::bug;
 use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::*;
 use rustc_middle::ty::layout::{LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout};
@@ -398,16 +399,8 @@
             }
             Rvalue::BinaryOp(op, box (left, right)) => {
                 trace!("checking BinaryOp(op = {:?}, left = {:?}, right = {:?})", op, left, right);
-                self.check_binary_op(*op, left, right, location)?;
-            }
-            Rvalue::CheckedBinaryOp(op, box (left, right)) => {
-                trace!(
-                    "checking CheckedBinaryOp(op = {:?}, left = {:?}, right = {:?})",
-                    op,
-                    left,
-                    right
-                );
-                self.check_binary_op(*op, left, right, location)?;
+                let op = op.overflowing_to_wrapping().unwrap_or(*op);
+                self.check_binary_op(op, left, right, location)?;
             }
 
             // Do not try creating references (#67862)
@@ -554,24 +547,18 @@
                 let right = self.eval_operand(right)?;
                 let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?;
 
-                let val =
-                    self.use_ecx(|this| this.ecx.wrapping_binary_op(bin_op, &left, &right))?;
-                val.into()
-            }
-
-            CheckedBinaryOp(bin_op, box (ref left, ref right)) => {
-                let left = self.eval_operand(left)?;
-                let left = self.use_ecx(|this| this.ecx.read_immediate(&left))?;
-
-                let right = self.eval_operand(right)?;
-                let right = self.use_ecx(|this| this.ecx.read_immediate(&right))?;
-
-                let (val, overflowed) =
-                    self.use_ecx(|this| this.ecx.overflowing_binary_op(bin_op, &left, &right))?;
-                let overflowed = ImmTy::from_bool(overflowed, self.tcx);
-                Value::Aggregate {
-                    variant: VariantIdx::ZERO,
-                    fields: [Value::from(val), overflowed.into()].into_iter().collect(),
+                if let Some(bin_op) = bin_op.overflowing_to_wrapping() {
+                    let (val, overflowed) =
+                        self.use_ecx(|this| this.ecx.overflowing_binary_op(bin_op, &left, &right))?;
+                    let overflowed = ImmTy::from_bool(overflowed, self.tcx);
+                    Value::Aggregate {
+                        variant: VariantIdx::ZERO,
+                        fields: [Value::from(val), overflowed.into()].into_iter().collect(),
+                    }
+                } else {
+                    let val =
+                        self.use_ecx(|this| this.ecx.wrapping_binary_op(bin_op, &left, &right))?;
+                    val.into()
                 }
             }
 
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index 8be96b6..e407929 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -1,7 +1,7 @@
-use crate::rustc_middle::ty::util::IntTypeExt;
 use rustc_data_structures::fx::FxHashMap;
 use rustc_middle::mir::interpret::AllocId;
 use rustc_middle::mir::*;
+use rustc_middle::ty::util::IntTypeExt;
 use rustc_middle::ty::{self, AdtDef, ParamEnv, Ty, TyCtxt};
 use rustc_session::Session;
 use rustc_target::abi::{HasDataLayout, Size, TagEncoding, Variants};
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index e69c5da..9af48f0 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -16,8 +16,6 @@
 
 #[macro_use]
 extern crate tracing;
-#[macro_use]
-extern crate rustc_middle;
 
 use hir::ConstContext;
 use required_consts::RequiredConstsVisitor;
@@ -38,6 +36,7 @@
 use rustc_middle::query;
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 use rustc_middle::util::Providers;
+use rustc_middle::{bug, span_bug};
 use rustc_span::{source_map::Spanned, sym, DUMMY_SP};
 use rustc_trait_selection::traits;
 
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index da63fcf..221301b 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -2,6 +2,7 @@
 
 use rustc_middle::mir::*;
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::sym;
 
 pub struct LowerIntrinsics;
@@ -139,16 +140,16 @@
                                 rhs = args.next().unwrap();
                             }
                             let bin_op = match intrinsic.name {
-                                sym::add_with_overflow => BinOp::Add,
-                                sym::sub_with_overflow => BinOp::Sub,
-                                sym::mul_with_overflow => BinOp::Mul,
+                                sym::add_with_overflow => BinOp::AddWithOverflow,
+                                sym::sub_with_overflow => BinOp::SubWithOverflow,
+                                sym::mul_with_overflow => BinOp::MulWithOverflow,
                                 _ => bug!("unexpected intrinsic"),
                             };
                             block.statements.push(Statement {
                                 source_info: terminator.source_info,
                                 kind: StatementKind::Assign(Box::new((
                                     *destination,
-                                    Rvalue::CheckedBinaryOp(bin_op, Box::new((lhs.node, rhs.node))),
+                                    Rvalue::BinaryOp(bin_op, Box::new((lhs.node, rhs.node))),
                                 ))),
                             });
                             terminator.kind = TerminatorKind::Goto { target };
diff --git a/compiler/rustc_mir_transform/src/mentioned_items.rs b/compiler/rustc_mir_transform/src/mentioned_items.rs
index 57b6126..db2bb60 100644
--- a/compiler/rustc_mir_transform/src/mentioned_items.rs
+++ b/compiler/rustc_mir_transform/src/mentioned_items.rs
@@ -79,8 +79,8 @@
                 // add everything that may involve a vtable.
                 let source_ty = operand.ty(self.body, self.tcx);
                 let may_involve_vtable = match (
-                    source_ty.builtin_deref(true).map(|t| t.ty.kind()),
-                    target_ty.builtin_deref(true).map(|t| t.ty.kind()),
+                    source_ty.builtin_deref(true).map(|t| t.kind()),
+                    target_ty.builtin_deref(true).map(|t| t.kind()),
                 ) {
                     (Some(ty::Array(..)), Some(ty::Str | ty::Slice(..))) => false, // &str/&[T] unsizing
                     _ => true,
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
index c26a546..2070895 100644
--- a/compiler/rustc_mir_transform/src/normalize_array_len.rs
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -48,9 +48,9 @@
                 let operand_ty = operand.ty(body, tcx);
                 debug!(?operand_ty);
                 if let Some(operand_ty) = operand_ty.builtin_deref(true)
-                    && let ty::Array(_, len) = operand_ty.ty.kind()
+                    && let ty::Array(_, len) = operand_ty.kind()
                     && let Some(cast_ty) = cast_ty.builtin_deref(true)
-                    && let ty::Slice(..) = cast_ty.ty.kind()
+                    && let ty::Slice(..) = cast_ty.kind()
                 {
                     slice_lengths[local] = Some(*len);
                 }
diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
index 232c290..885dbd5 100644
--- a/compiler/rustc_mir_transform/src/nrvo.rs
+++ b/compiler/rustc_mir_transform/src/nrvo.rs
@@ -2,6 +2,7 @@
 
 use rustc_hir::Mutability;
 use rustc_index::bit_set::BitSet;
+use rustc_middle::bug;
 use rustc_middle::mir::visit::{MutVisitor, NonUseContext, PlaceContext, Visitor};
 use rustc_middle::mir::{self, BasicBlock, Local, Location};
 use rustc_middle::ty::TyCtxt;
diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs
index 689a547..34aa31b 100644
--- a/compiler/rustc_mir_transform/src/promote_consts.rs
+++ b/compiler/rustc_mir_transform/src/promote_consts.rs
@@ -20,6 +20,7 @@
 use rustc_middle::mir::*;
 use rustc_middle::ty::GenericArgs;
 use rustc_middle::ty::{self, List, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 
 use rustc_index::{Idx, IndexSlice, IndexVec};
@@ -469,7 +470,7 @@
                 self.validate_operand(operand)?;
             }
 
-            Rvalue::BinaryOp(op, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(op, box (lhs, rhs)) => {
+            Rvalue::BinaryOp(op, box (lhs, rhs)) => {
                 let op = *op;
                 let lhs_ty = lhs.ty(self.body, self.tcx);
 
@@ -538,10 +539,13 @@
                     | BinOp::Offset
                     | BinOp::Add
                     | BinOp::AddUnchecked
+                    | BinOp::AddWithOverflow
                     | BinOp::Sub
                     | BinOp::SubUnchecked
+                    | BinOp::SubWithOverflow
                     | BinOp::Mul
                     | BinOp::MulUnchecked
+                    | BinOp::MulWithOverflow
                     | BinOp::BitXor
                     | BinOp::BitAnd
                     | BinOp::BitOr
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
index 044ae32..801ef14 100644
--- a/compiler/rustc_mir_transform/src/ref_prop.rs
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -1,6 +1,7 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_index::bit_set::BitSet;
 use rustc_index::IndexVec;
+use rustc_middle::bug;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
 use rustc_middle::ty::TyCtxt;
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 1c85a60..dcf54ad 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -5,6 +5,7 @@
 use rustc_middle::query::Providers;
 use rustc_middle::ty::GenericArgs;
 use rustc_middle::ty::{self, CoroutineArgs, EarlyBinder, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
 
 use rustc_index::{Idx, IndexVec};
@@ -1046,7 +1047,7 @@
                 args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
             ),
             sig.c_variadic,
-            sig.unsafety,
+            sig.safety,
             sig.abi,
         )
     });
diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
index 80eadb9..f4481c2 100644
--- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
+++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs
@@ -14,6 +14,7 @@
 use rustc_middle::ty::adjustment::PointerCoercion;
 use rustc_middle::ty::util::Discr;
 use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_span::source_map::respan;
 use rustc_span::{Span, Symbol};
 use rustc_target::abi::{FieldIdx, VariantIdx};
@@ -534,8 +535,7 @@
             }
 
             // If projection of Discriminant then compare with `Ty::discriminant_ty`
-            if let ty::Alias(ty::AliasKind::Projection, ty::AliasTy { args, def_id, .. }) =
-                expected_ty.kind()
+            if let ty::Alias(ty::Projection, ty::AliasTy { args, def_id, .. }) = expected_ty.kind()
                 && Some(*def_id) == self.tcx.lang_items().discriminant_type()
                 && args.first().unwrap().as_type().unwrap().discriminant_ty(self.tcx) == operand_ty
             {
diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
index 1a8cfc4..03907ba 100644
--- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
@@ -2,6 +2,7 @@
 
 use super::MirPass;
 use rustc_middle::{
+    bug,
     mir::{
         interpret::Scalar, BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement,
         StatementKind, SwitchTargets, TerminatorKind,
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index 06d5e17..cdf3305 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -1,6 +1,7 @@
 use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
 use rustc_index::bit_set::{BitSet, GrowableBitSet};
 use rustc_index::IndexVec;
+use rustc_middle::bug;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs
index 55fed7d..fb87042 100644
--- a/compiler/rustc_mir_transform/src/ssa.rs
+++ b/compiler/rustc_mir_transform/src/ssa.rs
@@ -9,6 +9,7 @@
 use rustc_data_structures::graph::dominators::Dominators;
 use rustc_index::bit_set::BitSet;
 use rustc_index::{IndexSlice, IndexVec};
+use rustc_middle::bug;
 use rustc_middle::middle::resolve_bound_vars::Set1;
 use rustc_middle::mir::visit::*;
 use rustc_middle::mir::*;
diff --git a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
index 66b6235..1404a45 100644
--- a/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_enum_branching.rs
@@ -2,6 +2,7 @@
 
 use crate::MirPass;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_middle::bug;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::{
     BasicBlock, BasicBlockData, BasicBlocks, Body, Local, Operand, Rvalue, StatementKind,
diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs
index 8ad7bc39..a6c3c3b 100644
--- a/compiler/rustc_mir_transform/src/unreachable_prop.rs
+++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs
@@ -3,6 +3,7 @@
 //! post-order traversal of the blocks.
 
 use rustc_data_structures::fx::FxHashSet;
+use rustc_middle::bug;
 use rustc_middle::mir::interpret::Scalar;
 use rustc_middle::mir::patch::MirPatch;
 use rustc_middle::mir::*;
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index dd10655..4b43564 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1429,7 +1429,7 @@
         match self.tcx.def_kind(id.owner_id) {
             DefKind::Enum | DefKind::Struct | DefKind::Union => {
                 if self.strategy == MonoItemCollectionStrategy::Eager
-                    && self.tcx.generics_of(id.owner_id).count() == 0
+                    && self.tcx.generics_of(id.owner_id).is_empty()
                 {
                     debug!("RootCollector: ADT drop-glue for `{id:?}`",);
 
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index cbab200..ddfb42a 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -32,10 +32,9 @@
     source_ty: Ty<'tcx>,
     target_ty: Ty<'tcx>,
 ) -> Result<CustomCoerceUnsized, ErrorGuaranteed> {
-    let trait_ref = ty::TraitRef::from_lang_item(
+    let trait_ref = ty::TraitRef::new(
         tcx.tcx,
-        LangItem::CoerceUnsized,
-        tcx.span,
+        tcx.require_lang_item(LangItem::CoerceUnsized, Some(tcx.span)),
         [source_ty, target_ty],
     );
 
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index 6d237df..14ebe27 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -51,7 +51,7 @@
     debug!(?generics);
 
     // Exit early when there are no parameters to be unused.
-    if generics.count() == 0 {
+    if generics.is_empty() {
         return UnusedGenericParams::new_all_used();
     }
 
@@ -131,7 +131,7 @@
 ) {
     match tcx.def_kind(def_id) {
         DefKind::Closure => {
-            for param in &generics.params {
+            for param in &generics.own_params {
                 debug!(?param, "(closure/gen)");
                 unused_parameters.mark_used(param.index);
             }
@@ -165,7 +165,7 @@
         | DefKind::LifetimeParam
         | DefKind::GlobalAsm
         | DefKind::Impl { .. } => {
-            for param in &generics.params {
+            for param in &generics.own_params {
                 debug!(?param, "(other)");
                 if let ty::GenericParamDefKind::Lifetime = param.kind {
                     unused_parameters.mark_used(param.index);
@@ -202,7 +202,7 @@
     let mut param_names = Vec::new();
     let mut next_generics = Some(generics);
     while let Some(generics) = next_generics {
-        for param in &generics.params {
+        for param in &generics.own_params {
             if unused_parameters.is_unused(param.index) {
                 debug!(?param);
                 let def_span = tcx.def_span(param.def_id);
diff --git a/compiler/rustc_next_trait_solver/Cargo.toml b/compiler/rustc_next_trait_solver/Cargo.toml
index 9d496fd..8bcc21d 100644
--- a/compiler/rustc_next_trait_solver/Cargo.toml
+++ b/compiler/rustc_next_trait_solver/Cargo.toml
@@ -5,9 +5,19 @@
 
 [dependencies]
 rustc_type_ir = { path = "../rustc_type_ir", default-features = false }
+derivative = "2.2.0"
+rustc_macros = { path = "../rustc_macros", optional = true }
+rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
+rustc_serialize = { path = "../rustc_serialize", optional = true }
+rustc_data_structures = { path = "../rustc_data_structures", optional = true }
+rustc_ast_ir = { path = "../rustc_ast_ir", default-features = false }
 
 [features]
 default = ["nightly"]
 nightly = [
     "rustc_type_ir/nightly",
-]
\ No newline at end of file
+    "rustc_macros",
+    "rustc_serialize",
+    "rustc_data_structures",
+    "rustc_ast_ir/nightly",
+]
diff --git a/compiler/rustc_next_trait_solver/src/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
index c437ded..127ebde 100644
--- a/compiler/rustc_next_trait_solver/src/canonicalizer.rs
+++ b/compiler/rustc_next_trait_solver/src/canonicalizer.rs
@@ -1,11 +1,11 @@
 use std::cmp::Ordering;
 
 use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
-use rustc_type_ir::new::{Const, Region, Ty};
+use rustc_type_ir::inherent::*;
 use rustc_type_ir::visit::TypeVisitableExt;
 use rustc_type_ir::{
-    self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, ConstTy,
-    InferCtxtLike, Interner, IntoKind, PlaceholderLike,
+    self as ty, Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, InferCtxtLike,
+    Interner,
 };
 
 /// Whether we're canonicalizing a query input or the query response.
@@ -217,10 +217,9 @@
         self.infcx.interner()
     }
 
-    fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T>
+    fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
     where
         T: TypeFoldable<I>,
-        I::Binder<T>: TypeSuperFoldable<I>,
     {
         self.binder_index.shift_in(1);
         let t = t.super_fold_with(self);
@@ -268,7 +267,7 @@
             ty::ReVar(vid) => {
                 assert_eq!(
                     self.infcx.opportunistic_resolve_lt_var(vid),
-                    None,
+                    r,
                     "region vid should have been resolved fully before canonicalization"
                 );
                 match self.canonicalize_mode {
@@ -302,13 +301,8 @@
             ty::Infer(i) => match i {
                 ty::TyVar(vid) => {
                     assert_eq!(
-                        self.infcx.root_ty_var(vid),
-                        vid,
-                        "ty vid should have been resolved fully before canonicalization"
-                    );
-                    assert_eq!(
-                        self.infcx.probe_ty_var(vid),
-                        None,
+                        self.infcx.opportunistic_resolve_ty_var(vid),
+                        t,
                         "ty vid should have been resolved fully before canonicalization"
                     );
 
@@ -318,10 +312,24 @@
                             .unwrap_or_else(|| panic!("ty var should have been resolved: {t:?}")),
                     ))
                 }
-                ty::IntVar(_) => CanonicalVarKind::Ty(CanonicalTyVarKind::Int),
-                ty::FloatVar(_) => CanonicalVarKind::Ty(CanonicalTyVarKind::Float),
+                ty::IntVar(vid) => {
+                    assert_eq!(
+                        self.infcx.opportunistic_resolve_int_var(vid),
+                        t,
+                        "ty vid should have been resolved fully before canonicalization"
+                    );
+                    CanonicalVarKind::Ty(CanonicalTyVarKind::Int)
+                }
+                ty::FloatVar(vid) => {
+                    assert_eq!(
+                        self.infcx.opportunistic_resolve_float_var(vid),
+                        t,
+                        "ty vid should have been resolved fully before canonicalization"
+                    );
+                    CanonicalVarKind::Ty(CanonicalTyVarKind::Float)
+                }
                 ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_) => {
-                    todo!()
+                    panic!("fresh vars not expected in canonicalization")
                 }
             },
             ty::Placeholder(placeholder) => match self.canonicalize_mode {
@@ -387,14 +395,11 @@
         let kind = match c.kind() {
             ty::ConstKind::Infer(i) => match i {
                 ty::InferConst::Var(vid) => {
+                    // We compare `kind`s here because we've folded the `ty` with `RegionsToStatic`
+                    // so we'll get a mismatch in types if it actually changed any regions.
                     assert_eq!(
-                        self.infcx.root_ct_var(vid),
-                        vid,
-                        "region vid should have been resolved fully before canonicalization"
-                    );
-                    assert_eq!(
-                        self.infcx.probe_ct_var(vid),
-                        None,
+                        self.infcx.opportunistic_resolve_ct_var(vid, ty).kind(),
+                        c.kind(),
                         "region vid should have been resolved fully before canonicalization"
                     );
                     CanonicalVarKind::Const(self.infcx.universe_of_ct(vid).unwrap(), ty)
@@ -449,10 +454,9 @@
         self.interner
     }
 
-    fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T>
+    fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
     where
         T: TypeFoldable<I>,
-        I::Binder<T>: TypeSuperFoldable<I>,
     {
         self.binder.shift_in(1);
         let t = t.super_fold_with(self);
diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs
index e5fc8f7..b913a05 100644
--- a/compiler/rustc_next_trait_solver/src/lib.rs
+++ b/compiler/rustc_next_trait_solver/src/lib.rs
@@ -1 +1,3 @@
 pub mod canonicalizer;
+pub mod resolve;
+pub mod solve;
diff --git a/compiler/rustc_next_trait_solver/src/resolve.rs b/compiler/rustc_next_trait_solver/src/resolve.rs
new file mode 100644
index 0000000..1333b4a
--- /dev/null
+++ b/compiler/rustc_next_trait_solver/src/resolve.rs
@@ -0,0 +1,83 @@
+use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_type_ir::inherent::*;
+use rustc_type_ir::visit::TypeVisitableExt;
+use rustc_type_ir::{self as ty, InferCtxtLike, Interner};
+
+///////////////////////////////////////////////////////////////////////////
+// EAGER RESOLUTION
+
+/// Resolves ty, region, and const vars to their inferred values or their root vars.
+pub struct EagerResolver<
+    'a,
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner = <Infcx as InferCtxtLike>::Interner,
+> {
+    infcx: &'a Infcx,
+}
+
+impl<'a, Infcx: InferCtxtLike> EagerResolver<'a, Infcx> {
+    pub fn new(infcx: &'a Infcx) -> Self {
+        EagerResolver { infcx }
+    }
+}
+
+impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> TypeFolder<I> for EagerResolver<'_, Infcx> {
+    fn interner(&self) -> I {
+        self.infcx.interner()
+    }
+
+    fn fold_ty(&mut self, t: I::Ty) -> I::Ty {
+        match t.kind() {
+            ty::Infer(ty::TyVar(vid)) => {
+                let resolved = self.infcx.opportunistic_resolve_ty_var(vid);
+                if t != resolved && resolved.has_infer() {
+                    resolved.fold_with(self)
+                } else {
+                    resolved
+                }
+            }
+            ty::Infer(ty::IntVar(vid)) => self.infcx.opportunistic_resolve_int_var(vid),
+            ty::Infer(ty::FloatVar(vid)) => self.infcx.opportunistic_resolve_float_var(vid),
+            _ => {
+                if t.has_infer() {
+                    t.super_fold_with(self)
+                } else {
+                    t
+                }
+            }
+        }
+    }
+
+    fn fold_region(&mut self, r: I::Region) -> I::Region {
+        match r.kind() {
+            ty::ReVar(vid) => self.infcx.opportunistic_resolve_lt_var(vid),
+            _ => r,
+        }
+    }
+
+    fn fold_const(&mut self, c: I::Const) -> I::Const {
+        match c.kind() {
+            ty::ConstKind::Infer(ty::InferConst::Var(vid)) => {
+                let ty = c.ty().fold_with(self);
+                let resolved = self.infcx.opportunistic_resolve_ct_var(vid, ty);
+                if c != resolved && resolved.has_infer() {
+                    resolved.fold_with(self)
+                } else {
+                    resolved
+                }
+            }
+            ty::ConstKind::Infer(ty::InferConst::EffectVar(vid)) => {
+                let bool = Ty::new_bool(self.infcx.interner());
+                debug_assert_eq!(c.ty(), bool);
+                self.infcx.opportunistic_resolve_effect_var(vid, bool)
+            }
+            _ => {
+                if c.has_infer() {
+                    c.super_fold_with(self)
+                } else {
+                    c
+                }
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_next_trait_solver/src/solve.rs b/compiler/rustc_next_trait_solver/src/solve.rs
new file mode 100644
index 0000000..eba96fa
--- /dev/null
+++ b/compiler/rustc_next_trait_solver/src/solve.rs
@@ -0,0 +1 @@
+pub use rustc_type_ir::solve::*;
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index 873095d..04f855e 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -401,10 +401,8 @@
     .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction
     .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction
 
-parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
-
-parse_invalid_meta_item_unquoted_ident = expected unsuffixed literal, found `{$token}`
-    .suggestion = surround the identifier with quotation marks to parse it as a string
+parse_invalid_meta_item = expected unsuffixed literal, found `{$token}`
+    .quote_ident_sugg = surround the identifier with quotation marks to make it into a string literal
 
 parse_invalid_offset_of = offset_of expects dot-separated field and variant names
 
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index d06f03a..3f08a83 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -83,7 +83,7 @@
     #[suggestion(style = "short", code = "", applicability = "machine-applicable")]
     pub span: Span,
     #[help]
-    pub opt_help: Option<()>,
+    pub show_help: bool,
     pub name: &'a str,
 }
 
@@ -978,21 +978,13 @@
     #[primary_span]
     pub span: Span,
     pub token: Token,
-}
-
-#[derive(Diagnostic)]
-#[diag(parse_invalid_meta_item_unquoted_ident)]
-pub(crate) struct InvalidMetaItemUnquotedIdent {
-    #[primary_span]
-    pub span: Span,
-    pub token: Token,
     #[subdiagnostic]
-    pub sugg: InvalidMetaItemSuggQuoteIdent,
+    pub quote_ident_sugg: Option<InvalidMetaItemQuoteIdentSugg>,
 }
 
 #[derive(Subdiagnostic)]
-#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
-pub(crate) struct InvalidMetaItemSuggQuoteIdent {
+#[multipart_suggestion(parse_quote_ident_sugg, applicability = "machine-applicable")]
+pub(crate) struct InvalidMetaItemQuoteIdentSugg {
     #[suggestion_part(code = "\"")]
     pub before: Span,
     #[suggestion_part(code = "\"")]
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index d2d200a..6eb8bed 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -370,11 +370,10 @@
         let content = self.str_from(content_start);
         if contains_text_flow_control_chars(content) {
             let span = self.mk_sp(start, self.pos);
-            self.psess.buffer_lint_with_diagnostic(
+            self.psess.buffer_lint(
                 TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
                 span,
                 ast::CRATE_NODE_ID,
-                "unicode codepoint changing visible direction of text present in comment",
                 BuiltinLintDiag::UnicodeTextFlow(span, content.to_string()),
             );
         }
@@ -723,12 +722,11 @@
             self.dcx().emit_err(errors::UnknownPrefix { span: prefix_span, prefix, sugg });
         } else {
             // Before Rust 2021, only emit a lint for migration.
-            self.psess.buffer_lint_with_diagnostic(
+            self.psess.buffer_lint(
                 RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
                 prefix_span,
                 ast::CRATE_NODE_ID,
-                format!("prefix `{prefix}` is unknown"),
-                BuiltinLintDiag::ReservedPrefix(prefix_span),
+                BuiltinLintDiag::ReservedPrefix(prefix_span, prefix.to_string()),
             );
         }
     }
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index b5a5a2a..eabe022 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -241,7 +241,7 @@
         // we have no way of tracking this in the lexer itself, so we piggyback on the parser
         let mut in_cond = false;
         while parser.token != token::Eof {
-            if let Err(diff_err) = parser.err_diff_marker() {
+            if let Err(diff_err) = parser.err_vcs_conflict_marker() {
                 diff_errs.push(diff_err);
             } else if parser.is_keyword_ahead(0, &[kw::If, kw::While]) {
                 in_cond = true;
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index ab5f51e..a57eb70 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -1,7 +1,4 @@
-use crate::errors::{
-    InvalidMetaItem, InvalidMetaItemSuggQuoteIdent, InvalidMetaItemUnquotedIdent,
-    SuffixedLiteralInAttribute,
-};
+use crate::errors;
 use crate::fluent_generated as fluent;
 use crate::maybe_whole;
 
@@ -318,7 +315,7 @@
         debug!("checking if {:?} is unsuffixed", lit);
 
         if !lit.kind.is_unsuffixed() {
-            self.dcx().emit_err(SuffixedLiteralInAttribute { span: lit.span });
+            self.dcx().emit_err(errors::SuffixedLiteralInAttribute { span: lit.span });
         }
 
         Ok(lit)
@@ -356,16 +353,17 @@
         Ok(nmis)
     }
 
-    /// Matches the following grammar (per RFC 1559).
+    /// Parse a meta item per RFC 1559.
+    ///
     /// ```ebnf
-    /// meta_item : PATH ( '=' UNSUFFIXED_LIT | '(' meta_item_inner? ')' )? ;
-    /// meta_item_inner : (meta_item | UNSUFFIXED_LIT) (',' meta_item_inner)? ;
+    /// MetaItem = SimplePath ( '=' UNSUFFIXED_LIT | '(' MetaSeq? ')' )? ;
+    /// MetaSeq = MetaItemInner (',' MetaItemInner)* ','? ;
     /// ```
     pub fn parse_meta_item(&mut self) -> PResult<'a, ast::MetaItem> {
         // We can't use `maybe_whole` here because it would bump in the `None`
         // case, which we don't want.
         if let token::Interpolated(nt) = &self.token.kind
-            && let token::NtMeta(attr_item) = &nt.0
+            && let token::NtMeta(attr_item) = &**nt
         {
             match attr_item.meta(attr_item.path.span) {
                 Some(meta) => {
@@ -387,7 +385,6 @@
         Ok(if self.eat(&token::Eq) {
             ast::MetaItemKind::NameValue(self.parse_unsuffixed_meta_item_lit()?)
         } else if self.check(&token::OpenDelim(Delimiter::Parenthesis)) {
-            // Matches `meta_seq = ( COMMASEP(meta_item_inner) )`.
             let (list, _) = self.parse_paren_comma_seq(|p| p.parse_meta_item_inner())?;
             ast::MetaItemKind::List(list)
         } else {
@@ -395,38 +392,45 @@
         })
     }
 
-    /// Matches `meta_item_inner : (meta_item | UNSUFFIXED_LIT) ;`.
+    /// Parse an inner meta item per RFC 1559.
+    ///
+    /// ```ebnf
+    /// MetaItemInner = UNSUFFIXED_LIT | MetaItem ;
+    /// ```
     fn parse_meta_item_inner(&mut self) -> PResult<'a, ast::NestedMetaItem> {
         match self.parse_unsuffixed_meta_item_lit() {
             Ok(lit) => return Ok(ast::NestedMetaItem::Lit(lit)),
-            Err(err) => err.cancel(),
+            Err(err) => err.cancel(), // we provide a better error below
         }
 
         match self.parse_meta_item() {
             Ok(mi) => return Ok(ast::NestedMetaItem::MetaItem(mi)),
-            Err(err) => err.cancel(),
+            Err(err) => err.cancel(), // we provide a better error below
         }
 
-        let token = self.token.clone();
+        let mut err = errors::InvalidMetaItem {
+            span: self.token.span,
+            token: self.token.clone(),
+            quote_ident_sugg: None,
+        };
 
-        // Check for unquoted idents in meta items, e.g.: #[cfg(key = foo)]
-        // `from_expansion()` ensures we don't suggest for cases such as
-        // `#[cfg(feature = $expr)]` in macros
-        if self.prev_token == token::Eq && !self.token.span.from_expansion() {
+        // Suggest quoting idents, e.g. in `#[cfg(key = value)]`. We don't use `Token::ident` and
+        // don't `uninterpolate` the token to avoid suggesting anything butchered or questionable
+        // when macro metavariables are involved.
+        if self.prev_token == token::Eq
+            && let token::Ident(..) = self.token.kind
+        {
             let before = self.token.span.shrink_to_lo();
-            while matches!(self.token.kind, token::Ident(..)) {
+            while let token::Ident(..) = self.token.kind {
                 self.bump();
             }
-            let after = self.prev_token.span.shrink_to_hi();
-            let sugg = InvalidMetaItemSuggQuoteIdent { before, after };
-            return Err(self.dcx().create_err(InvalidMetaItemUnquotedIdent {
-                span: token.span,
-                token,
-                sugg,
-            }));
+            err.quote_ident_sugg = Some(errors::InvalidMetaItemQuoteIdentSugg {
+                before,
+                after: self.prev_token.span.shrink_to_hi(),
+            });
         }
 
-        Err(self.dcx().create_err(InvalidMetaItem { span: token.span, token }))
+        Err(self.dcx().create_err(err))
     }
 }
 
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index f256dbf..ac12787 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -22,7 +22,6 @@
 use crate::parser;
 use crate::parser::attr::InnerAttrPolicy;
 use ast::token::IdentIsRaw;
-use parser::Recovered;
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, Lit, LitKind, Token, TokenKind};
@@ -31,7 +30,7 @@
 use rustc_ast::{
     AngleBracketedArg, AngleBracketedArgs, AnonConst, AttrVec, BinOpKind, BindingMode, Block,
     BlockCheckMode, Expr, ExprKind, GenericArg, Generics, HasTokens, Item, ItemKind, Param, Pat,
-    PatKind, Path, PathSegment, QSelf, Ty, TyKind,
+    PatKind, Path, PathSegment, QSelf, Recovered, Ty, TyKind,
 };
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashSet;
@@ -527,14 +526,14 @@
                 //
                 //   let x = 32:
                 //   let y = 42;
-                self.dcx().emit_err(ExpectedSemi {
+                let guar = self.dcx().emit_err(ExpectedSemi {
                     span: self.token.span,
                     token: self.token.clone(),
                     unexpected_token_label: None,
                     sugg: ExpectedSemiSugg::ChangeToSemi(self.token.span),
                 });
                 self.bump();
-                return Ok(Recovered::Yes);
+                return Ok(Recovered::Yes(guar));
             } else if self.look_ahead(0, |t| {
                 t == &token::CloseDelim(Delimiter::Brace)
                     || ((t.can_begin_expr() || t.can_begin_item())
@@ -552,13 +551,13 @@
                 //   let x = 32
                 //   let y = 42;
                 let span = self.prev_token.span.shrink_to_hi();
-                self.dcx().emit_err(ExpectedSemi {
+                let guar = self.dcx().emit_err(ExpectedSemi {
                     span,
                     token: self.token.clone(),
                     unexpected_token_label: Some(self.token.span),
                     sugg: ExpectedSemiSugg::AddSemi(span),
                 });
-                return Ok(Recovered::Yes);
+                return Ok(Recovered::Yes(guar));
             }
         }
 
@@ -712,8 +711,8 @@
 
         if self.check_too_many_raw_str_terminators(&mut err) {
             if expected.contains(&TokenType::Token(token::Semi)) && self.eat(&token::Semi) {
-                err.emit();
-                return Ok(Recovered::Yes);
+                let guar = err.emit();
+                return Ok(Recovered::Yes(guar));
             } else {
                 return Err(err);
             }
@@ -1224,7 +1223,11 @@
             let x = self.parse_seq_to_before_end(
                 &token::Gt,
                 SeqSep::trailing_allowed(token::Comma),
-                |p| p.parse_generic_arg(None),
+                |p| match p.parse_generic_arg(None)? {
+                    Some(arg) => Ok(arg),
+                    // If we didn't eat a generic arg, then we should error.
+                    None => p.unexpected_any(),
+                },
             );
             match x {
                 Ok((_, _, Recovered::No)) => {
@@ -1251,7 +1254,7 @@
                         }
                     }
                 }
-                Ok((_, _, Recovered::Yes)) => {}
+                Ok((_, _, Recovered::Yes(_))) => {}
                 Err(err) => {
                     err.cancel();
                 }
@@ -1284,13 +1287,13 @@
 
     /// Check to see if a pair of chained operators looks like an attempt at chained comparison,
     /// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
-    /// parenthesising the leftmost comparison.
+    /// parenthesising the leftmost comparison. The return value indicates if recovery happened.
     fn attempt_chained_comparison_suggestion(
         &mut self,
         err: &mut ComparisonOperatorsCannotBeChained,
         inner_op: &Expr,
         outer_op: &Spanned<AssocOp>,
-    ) -> Recovered {
+    ) -> bool {
         if let ExprKind::Binary(op, l1, r1) = &inner_op.kind {
             if let ExprKind::Field(_, ident) = l1.kind
                 && ident.as_str().parse::<i32>().is_err()
@@ -1298,7 +1301,7 @@
             {
                 // The parser has encountered `foo.bar<baz`, the likelihood of the turbofish
                 // suggestion being the only one to apply is high.
-                return Recovered::No;
+                return false;
             }
             return match (op.node, &outer_op.node) {
                 // `x == y == z`
@@ -1317,7 +1320,7 @@
                         span: inner_op.span.shrink_to_hi(),
                         middle_term: expr_to_str(r1),
                     });
-                    Recovered::No // Keep the current parse behavior, where the AST is `(x < y) < z`.
+                    false // Keep the current parse behavior, where the AST is `(x < y) < z`.
                 }
                 // `x == y < z`
                 (BinOpKind::Eq, AssocOp::Less | AssocOp::LessEqual | AssocOp::Greater | AssocOp::GreaterEqual) => {
@@ -1331,12 +1334,12 @@
                                 left: r1.span.shrink_to_lo(),
                                 right: r2.span.shrink_to_hi(),
                             });
-                            Recovered::Yes
+                            true
                         }
                         Err(expr_err) => {
                             expr_err.cancel();
                             self.restore_snapshot(snapshot);
-                            Recovered::Yes
+                            true
                         }
                     }
                 }
@@ -1351,19 +1354,19 @@
                                 left: l1.span.shrink_to_lo(),
                                 right: r1.span.shrink_to_hi(),
                             });
-                            Recovered::Yes
+                            true
                         }
                         Err(expr_err) => {
                             expr_err.cancel();
                             self.restore_snapshot(snapshot);
-                            Recovered::No
+                            false
                         }
                     }
                 }
-                _ => Recovered::No,
+                _ => false
             };
         }
-        Recovered::No
+        false
     }
 
     /// Produces an error if comparison operators are chained (RFC #558).
@@ -1494,7 +1497,7 @@
                         // misformatted turbofish, for instance), suggest a correct form.
                         let recovered = self
                             .attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
-                        if matches!(recovered, Recovered::Yes) {
+                        if recovered {
                             let guar = self.dcx().emit_err(err);
                             mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar)
                         } else {
@@ -1503,10 +1506,10 @@
                         }
                     };
                 }
-                let recover =
+                let recovered =
                     self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op);
                 let guar = self.dcx().emit_err(err);
-                if matches!(recover, Recovered::Yes) {
+                if recovered {
                     return mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar);
                 }
             }
@@ -1814,34 +1817,31 @@
         Ok(P(T::recovered(Some(P(QSelf { ty, path_span, position: 0 })), path)))
     }
 
-    pub fn maybe_consume_incorrect_semicolon(&mut self, items: &[P<Item>]) -> bool {
-        if self.token.kind == TokenKind::Semi {
-            self.bump();
+    /// This function gets called in places where a semicolon is NOT expected and if there's a
+    /// semicolon it emits the appropriate error and returns true.
+    pub fn maybe_consume_incorrect_semicolon(&mut self, previous_item: Option<&Item>) -> bool {
+        if self.token.kind != TokenKind::Semi {
+            return false;
+        }
 
-            let mut err =
-                IncorrectSemicolon { span: self.prev_token.span, opt_help: None, name: "" };
-
-            if !items.is_empty() {
-                let previous_item = &items[items.len() - 1];
-                let previous_item_kind_name = match previous_item.kind {
+        // Check previous item to add it to the diagnostic, for example to say
+        // `enum declarations are not followed by a semicolon`
+        let err = match previous_item {
+            Some(previous_item) => {
+                let name = match previous_item.kind {
                     // Say "braced struct" because tuple-structs and
                     // braceless-empty-struct declarations do take a semicolon.
-                    ItemKind::Struct(..) => Some("braced struct"),
-                    ItemKind::Enum(..) => Some("enum"),
-                    ItemKind::Trait(..) => Some("trait"),
-                    ItemKind::Union(..) => Some("union"),
-                    _ => None,
+                    ItemKind::Struct(..) => "braced struct",
+                    _ => previous_item.kind.descr(),
                 };
-                if let Some(name) = previous_item_kind_name {
-                    err.opt_help = Some(());
-                    err.name = name;
-                }
+                IncorrectSemicolon { span: self.token.span, name, show_help: true }
             }
-            self.dcx().emit_err(err);
-            true
-        } else {
-            false
-        }
+            None => IncorrectSemicolon { span: self.token.span, name: "", show_help: false },
+        };
+        self.dcx().emit_err(err);
+
+        self.bump();
+        true
     }
 
     /// Creates a `Diag` for an unexpected token `t` and tries to recover if it is a
@@ -2369,9 +2369,9 @@
         // in a subsequent macro invocation (#71039).
         let mut tok = self.token.clone();
         let mut labels = vec![];
-        while let TokenKind::Interpolated(node) = &tok.kind {
-            let tokens = node.0.tokens();
-            labels.push(node.clone());
+        while let TokenKind::Interpolated(nt) = &tok.kind {
+            let tokens = nt.tokens();
+            labels.push(nt.clone());
             if let Some(tokens) = tokens
                 && let tokens = tokens.to_attr_token_stream()
                 && let tokens = tokens.0.deref()
@@ -2384,27 +2384,20 @@
         }
         let mut iter = labels.into_iter().peekable();
         let mut show_link = false;
-        while let Some(node) = iter.next() {
-            let descr = node.0.descr();
+        while let Some(nt) = iter.next() {
+            let descr = nt.descr();
             if let Some(next) = iter.peek() {
-                let next_descr = next.0.descr();
+                let next_descr = next.descr();
                 if next_descr != descr {
-                    err.span_label(next.1, format!("this macro fragment matcher is {next_descr}"));
-                    err.span_label(node.1, format!("this macro fragment matcher is {descr}"));
+                    err.span_label(next.use_span(), format!("this is expected to be {next_descr}"));
                     err.span_label(
-                        next.0.use_span(),
-                        format!("this is expected to be {next_descr}"),
-                    );
-                    err.span_label(
-                        node.0.use_span(),
+                        nt.use_span(),
                         format!(
                             "this is interpreted as {}, but it is expected to be {}",
                             next_descr, descr,
                         ),
                     );
                     show_link = true;
-                } else {
-                    err.span_label(node.1, "");
                 }
             }
         }
@@ -2961,13 +2954,23 @@
         err
     }
 
-    pub fn is_diff_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> bool {
+    /// This checks if this is a conflict marker, depending of the parameter passed.
+    ///
+    /// * `>>>>>`
+    /// * `=====`
+    /// * `<<<<<`
+    ///
+    pub fn is_vcs_conflict_marker(
+        &mut self,
+        long_kind: &TokenKind,
+        short_kind: &TokenKind,
+    ) -> bool {
         (0..3).all(|i| self.look_ahead(i, |tok| tok == long_kind))
             && self.look_ahead(3, |tok| tok == short_kind)
     }
 
-    fn diff_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> Option<Span> {
-        if self.is_diff_marker(long_kind, short_kind) {
+    fn conflict_marker(&mut self, long_kind: &TokenKind, short_kind: &TokenKind) -> Option<Span> {
+        if self.is_vcs_conflict_marker(long_kind, short_kind) {
             let lo = self.token.span;
             for _ in 0..4 {
                 self.bump();
@@ -2977,15 +2980,16 @@
         None
     }
 
-    pub fn recover_diff_marker(&mut self) {
-        if let Err(err) = self.err_diff_marker() {
+    pub fn recover_vcs_conflict_marker(&mut self) {
+        if let Err(err) = self.err_vcs_conflict_marker() {
             err.emit();
             FatalError.raise();
         }
     }
 
-    pub fn err_diff_marker(&mut self) -> PResult<'a, ()> {
-        let Some(start) = self.diff_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) else {
+    pub fn err_vcs_conflict_marker(&mut self) -> PResult<'a, ()> {
+        let Some(start) = self.conflict_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt)
+        else {
             return Ok(());
         };
         let mut spans = Vec::with_capacity(3);
@@ -2997,13 +3001,15 @@
             if self.token.kind == TokenKind::Eof {
                 break;
             }
-            if let Some(span) = self.diff_marker(&TokenKind::OrOr, &TokenKind::BinOp(token::Or)) {
+            if let Some(span) = self.conflict_marker(&TokenKind::OrOr, &TokenKind::BinOp(token::Or))
+            {
                 middlediff3 = Some(span);
             }
-            if let Some(span) = self.diff_marker(&TokenKind::EqEq, &TokenKind::Eq) {
+            if let Some(span) = self.conflict_marker(&TokenKind::EqEq, &TokenKind::Eq) {
                 middle = Some(span);
             }
-            if let Some(span) = self.diff_marker(&TokenKind::BinOp(token::Shr), &TokenKind::Gt) {
+            if let Some(span) = self.conflict_marker(&TokenKind::BinOp(token::Shr), &TokenKind::Gt)
+            {
                 spans.push(span);
                 end = Some(span);
                 break;
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 8ed2a6e..fd3f63a 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -3,7 +3,7 @@
 use super::pat::{CommaRecoveryMode, Expected, RecoverColon, RecoverComma};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{
-    AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Recovered, Restrictions,
+    AttrWrapper, BlockMode, ClosureSpans, ForceCollect, Parser, PathStyle, Restrictions,
     SemiColonMode, SeqSep, TokenExpectType, TokenType, Trailing, TrailingToken,
 };
 
@@ -11,7 +11,7 @@
 use crate::maybe_recover_from_interpolated_ty_qpath;
 use ast::mut_visit::{noop_visit_expr, MutVisitor};
 use ast::token::IdentIsRaw;
-use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment};
+use ast::{CoroutineKind, ForLoopKind, GenBlockKind, MatchKind, Pat, Path, PathSegment, Recovered};
 use core::mem;
 use core::ops::ControlFlow;
 use rustc_ast::ptr::P;
@@ -45,7 +45,7 @@
 macro_rules! maybe_whole_expr {
     ($p:expr) => {
         if let token::Interpolated(nt) = &$p.token.kind {
-            match &nt.0 {
+            match &**nt {
                 token::NtExpr(e) | token::NtLiteral(e) => {
                     let e = e.clone();
                     $p.bump();
@@ -497,8 +497,7 @@
 
     /// Checks if this expression is a successfully parsed statement.
     fn expr_is_complete(&self, e: &Expr) -> bool {
-        self.restrictions.contains(Restrictions::STMT_EXPR)
-            && !classify::expr_requires_semi_to_be_stmt(e)
+        self.restrictions.contains(Restrictions::STMT_EXPR) && classify::expr_is_complete(e)
     }
 
     /// Parses `x..y`, `x..=y`, and `x..`/`x..=`.
@@ -725,7 +724,9 @@
     /// Returns the span of expr if it was not interpolated, or the span of the interpolated token.
     fn interpolated_or_expr_span(&self, expr: &Expr) -> Span {
         match self.prev_token.kind {
-            TokenKind::Interpolated(..) => self.prev_token.span,
+            TokenKind::NtIdent(..) | TokenKind::NtLifetime(..) | TokenKind::Interpolated(..) => {
+                self.prev_token.span
+            }
             _ => expr.span,
         }
     }
@@ -1912,11 +1913,10 @@
                             | ExprKind::Block(_, None)
                     )
                 {
-                    self.psess.buffer_lint_with_diagnostic(
+                    self.psess.buffer_lint(
                         BREAK_WITH_LABEL_AND_LOOP,
                         lo.to(expr.span),
                         ast::CRATE_NODE_ID,
-                        "this labeled break expression is easy to confuse with an unlabeled break with a labeled value expression",
                         BuiltinLintDiag::BreakWithLabelAndLoop(expr.span),
                     );
                 }
@@ -2629,7 +2629,7 @@
 
         CondChecker::new(self).visit_expr(&mut cond);
 
-        if let ExprKind::Let(_, _, _, None) = cond.kind {
+        if let ExprKind::Let(_, _, _, Recovered::No) = cond.kind {
             // Remove the last feature gating of a `let` expression since it's stable.
             self.psess.gated_spans.ungate_last(sym::let_chains, cond.span);
         }
@@ -2639,7 +2639,7 @@
 
     /// Parses a `let $pat = $expr` pseudo-expression.
     fn parse_expr_let(&mut self, restrictions: Restrictions) -> PResult<'a, P<Expr>> {
-        let is_recovered = if !restrictions.contains(Restrictions::ALLOW_LET) {
+        let recovered = if !restrictions.contains(Restrictions::ALLOW_LET) {
             let err = errors::ExpectedExpressionFoundLet {
                 span: self.token.span,
                 reason: ForbiddenLetReason::OtherForbidden,
@@ -2650,10 +2650,10 @@
                 // This was part of a closure, the that part of the parser recover.
                 return Err(self.dcx().create_err(err));
             } else {
-                Some(self.dcx().emit_err(err))
+                Recovered::Yes(self.dcx().emit_err(err))
             }
         } else {
-            None
+            Recovered::No
         };
         self.bump(); // Eat `let` token
         let lo = self.prev_token.span;
@@ -2674,7 +2674,7 @@
         }
         let expr = self.parse_expr_assoc_with(1 + prec_let_scrutinee_needs_par(), None.into())?;
         let span = lo.to(expr.span);
-        Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span, is_recovered)))
+        Ok(self.mk_expr(span, ExprKind::Let(pat, expr, span, recovered)))
     }
 
     /// Parses an `else { ... }` expression (`else` token already eaten).
@@ -2691,8 +2691,33 @@
             let first_tok_span = self.token.span;
             match self.parse_expr() {
                 Ok(cond)
-                // If it's not a free-standing expression, and is followed by a block,
-                // then it's very likely the condition to an `else if`.
+                // Try to guess the difference between a "condition-like" vs
+                // "statement-like" expression.
+                //
+                // We are seeing the following code, in which $cond is neither
+                // ExprKind::Block nor ExprKind::If (the 2 cases wherein this
+                // would be valid syntax).
+                //
+                //     if ... {
+                //     } else $cond
+                //
+                // If $cond is "condition-like" such as ExprKind::Binary, we
+                // want to suggest inserting `if`.
+                //
+                //     if ... {
+                //     } else if a == b {
+                //            ^^
+                //     }
+                //
+                // If $cond is "statement-like" such as ExprKind::While then we
+                // want to suggest wrapping in braces.
+                //
+                //     if ... {
+                //     } else {
+                //            ^
+                //         while true {}
+                //     }
+                //     ^
                     if self.check(&TokenKind::OpenDelim(Delimiter::Brace))
                         && classify::expr_requires_semi_to_be_stmt(&cond) =>
                 {
@@ -2998,7 +3023,7 @@
         &mut self,
         first_expr: &P<Expr>,
         arrow_span: Span,
-    ) -> Option<P<Expr>> {
+    ) -> Option<(Span, ErrorGuaranteed)> {
         if self.token.kind != token::Semi {
             return None;
         }
@@ -3023,7 +3048,7 @@
                     errors::MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp }
                 },
             });
-            this.mk_expr_err(span, guar)
+            (span, guar)
         };
         // We might have either a `,` -> `;` typo, or a block without braces. We need
         // a more subtle parsing strategy.
@@ -3136,16 +3161,19 @@
                         err
                     })?;
 
-                let require_comma = classify::expr_requires_semi_to_be_stmt(&expr)
+                let require_comma = !classify::expr_is_complete(&expr)
                     && this.token != token::CloseDelim(Delimiter::Brace);
 
                 if !require_comma {
                     arm_body = Some(expr);
                     this.eat(&token::Comma);
                     Ok(Recovered::No)
-                } else if let Some(body) = this.parse_arm_body_missing_braces(&expr, arrow_span) {
+                } else if let Some((span, guar)) =
+                    this.parse_arm_body_missing_braces(&expr, arrow_span)
+                {
+                    let body = this.mk_expr_err(span, guar);
                     arm_body = Some(body);
-                    Ok(Recovered::Yes)
+                    Ok(Recovered::Yes(guar))
                 } else {
                     let expr_span = expr.span;
                     arm_body = Some(expr);
@@ -3223,10 +3251,10 @@
                         .is_ok();
                     if pattern_follows && snapshot.check(&TokenKind::FatArrow) {
                         err.cancel();
-                        this.dcx().emit_err(errors::MissingCommaAfterMatchArm {
+                        let guar = this.dcx().emit_err(errors::MissingCommaAfterMatchArm {
                             span: arm_span.shrink_to_hi(),
                         });
-                        return Ok(Recovered::Yes);
+                        return Ok(Recovered::Yes(guar));
                     }
                     Err(err)
                 });
@@ -3705,7 +3733,7 @@
     /// Parses `ident (COLON expr)?`.
     fn parse_expr_field(&mut self) -> PResult<'a, ExprField> {
         let attrs = self.parse_outer_attributes()?;
-        self.recover_diff_marker();
+        self.recover_vcs_conflict_marker();
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             let lo = this.token.span;
 
@@ -3904,15 +3932,16 @@
 
         let span = e.span;
         match e.kind {
-            ExprKind::Let(_, _, _, ref mut is_recovered @ None) => {
+            ExprKind::Let(_, _, _, ref mut recovered @ Recovered::No) => {
                 if let Some(reason) = self.forbid_let_reason {
-                    *is_recovered =
-                        Some(self.parser.dcx().emit_err(errors::ExpectedExpressionFoundLet {
+                    *recovered = Recovered::Yes(self.parser.dcx().emit_err(
+                        errors::ExpectedExpressionFoundLet {
                             span,
                             reason,
                             missing_let: self.missing_let,
                             comparison: self.comparison,
-                        }));
+                        },
+                    ));
                 } else {
                     self.parser.psess.gated_spans.gate(sym::let_chains, span);
                 }
@@ -3980,7 +4009,7 @@
                 self.visit_expr(op);
                 self.forbid_let_reason = forbid_let_reason;
             }
-            ExprKind::Let(_, _, _, Some(_))
+            ExprKind::Let(_, _, _, Recovered::Yes(_))
             | ExprKind::Array(_)
             | ExprKind::ConstBlock(_)
             | ExprKind::Lit(_)
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 848277c..f43ddad 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -1,8 +1,7 @@
 use super::diagnostics::{dummy_arg, ConsumeClosingDelim};
 use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
 use super::{
-    AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Recovered, Trailing,
-    TrailingToken,
+    AttrWrapper, FollowedByType, ForceCollect, Parser, PathStyle, Trailing, TrailingToken,
 };
 use crate::errors::{self, MacroExpandsToAdtField};
 use crate::fluent_generated as fluent;
@@ -34,7 +33,7 @@
 
     /// Parses a `mod <foo> { ... }` or `mod <foo>;` item.
     fn parse_item_mod(&mut self, attrs: &mut AttrVec) -> PResult<'a, ItemInfo> {
-        let unsafety = self.parse_unsafety(Case::Sensitive);
+        let safety = self.parse_safety(Case::Sensitive);
         self.expect_keyword(kw::Mod)?;
         let id = self.parse_ident()?;
         let mod_kind = if self.eat(&token::Semi) {
@@ -46,10 +45,11 @@
             attrs.extend(inner_attrs);
             ModKind::Loaded(items, Inline::Yes, inner_span)
         };
-        Ok((id, ItemKind::Mod(unsafety, mod_kind)))
+        Ok((id, ItemKind::Mod(safety, mod_kind)))
     }
 
     /// Parses the contents of a module (inner attributes followed by module items).
+    /// We exit once we hit `term`
     pub fn parse_mod(
         &mut self,
         term: &TokenKind,
@@ -58,15 +58,21 @@
         let attrs = self.parse_inner_attributes()?;
 
         let post_attr_lo = self.token.span;
-        let mut items = ThinVec::new();
-        while let Some(item) = self.parse_item(ForceCollect::No)? {
+        let mut items: ThinVec<P<_>> = ThinVec::new();
+
+        // There shouldn't be any stray semicolons before or after items.
+        // `parse_item` consumes the appropriate semicolons so any leftover is an error.
+        loop {
+            while self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {} // Eat all bad semicolons
+            let Some(item) = self.parse_item(ForceCollect::No)? else {
+                break;
+            };
             items.push(item);
-            self.maybe_consume_incorrect_semicolon(&items);
         }
 
         if !self.eat(term) {
             let token_str = super::token_descr(&self.token);
-            if !self.maybe_consume_incorrect_semicolon(&items) {
+            if !self.maybe_consume_incorrect_semicolon(items.last().map(|x| &**x)) {
                 let msg = format!("expected item, found {token_str}");
                 let mut err = self.dcx().struct_span_err(self.token.span, msg);
                 let span = self.token.span;
@@ -102,9 +108,9 @@
         fn_parse_mode: FnParseMode,
         force_collect: ForceCollect,
     ) -> PResult<'a, Option<Item>> {
-        self.recover_diff_marker();
+        self.recover_vcs_conflict_marker();
         let attrs = self.parse_outer_attributes()?;
-        self.recover_diff_marker();
+        self.recover_vcs_conflict_marker();
         self.parse_item_common(attrs, true, false, fn_parse_mode, force_collect)
     }
 
@@ -195,12 +201,12 @@
         fn_parse_mode: FnParseMode,
         case: Case,
     ) -> PResult<'a, Option<ItemInfo>> {
-        let def_final = def == &Defaultness::Final;
+        let check_pub = def == &Defaultness::Final;
         let mut def_ = || mem::replace(def, Defaultness::Final);
 
         let info = if self.eat_keyword_case(kw::Use, case) {
             self.parse_use_item()?
-        } else if self.check_fn_front_matter(def_final, case) {
+        } else if self.check_fn_front_matter(check_pub, case) {
             // FUNCTION ITEM
             let (ident, sig, generics, body) =
                 self.parse_fn(attrs, fn_parse_mode, lo, vis, case)?;
@@ -211,13 +217,13 @@
                 self.parse_item_extern_crate()?
             } else {
                 // EXTERN BLOCK
-                self.parse_item_foreign_mod(attrs, Unsafe::No)?
+                self.parse_item_foreign_mod(attrs, Safety::Default)?
             }
         } else if self.is_unsafe_foreign_mod() {
             // EXTERN BLOCK
-            let unsafety = self.parse_unsafety(Case::Sensitive);
+            let safety = self.parse_safety(Case::Sensitive);
             self.expect_keyword(kw::Extern)?;
-            self.parse_item_foreign_mod(attrs, unsafety)?
+            self.parse_item_foreign_mod(attrs, safety)?
         } else if self.is_static_global() {
             // STATIC ITEM
             self.bump(); // `static`
@@ -311,7 +317,7 @@
         Ok(Some(info))
     }
 
-    fn recover_import_as_use(&mut self) -> PResult<'a, Option<(Ident, ItemKind)>> {
+    fn recover_import_as_use(&mut self) -> PResult<'a, Option<ItemInfo>> {
         let span = self.token.span;
         let token_name = super::token_descr(&self.token);
         let snapshot = self.create_snapshot_for_diagnostic();
@@ -329,14 +335,14 @@
         }
     }
 
-    fn parse_use_item(&mut self) -> PResult<'a, (Ident, ItemKind)> {
+    fn parse_use_item(&mut self) -> PResult<'a, ItemInfo> {
         let tree = self.parse_use_tree()?;
         if let Err(mut e) = self.expect_semi() {
             match tree.kind {
                 UseTreeKind::Glob => {
                     e.note("the wildcard token must be last on the path");
                 }
-                UseTreeKind::Nested(..) => {
+                UseTreeKind::Nested { .. } => {
                     e.note("glob-like brace syntax must be last on the path");
                 }
                 _ => (),
@@ -541,7 +547,7 @@
         attrs: &mut AttrVec,
         defaultness: Defaultness,
     ) -> PResult<'a, ItemInfo> {
-        let unsafety = self.parse_unsafety(Case::Sensitive);
+        let safety = self.parse_safety(Case::Sensitive);
         self.expect_keyword(kw::Impl)?;
 
         // First, parse generic parameters if necessary.
@@ -647,7 +653,7 @@
                 let trait_ref = TraitRef { path, ref_id: ty_first.id };
 
                 ItemKind::Impl(Box::new(Impl {
-                    unsafety,
+                    safety,
                     polarity,
                     defaultness,
                     constness,
@@ -660,7 +666,7 @@
             None => {
                 // impl Type
                 ItemKind::Impl(Box::new(Impl {
-                    unsafety,
+                    safety,
                     polarity,
                     defaultness,
                     constness,
@@ -686,20 +692,35 @@
             (None, self.parse_path(PathStyle::Expr)?)
         };
 
-        let rename = if self.eat_keyword(kw::As) { Some(self.parse_ident()?) } else { None };
-
-        let body = if self.check(&token::OpenDelim(Delimiter::Brace)) {
-            Some(self.parse_block()?)
-        } else {
-            self.expect(&token::Semi)?;
-            None
+        let rename = |this: &mut Self| {
+            Ok(if this.eat_keyword(kw::As) { Some(this.parse_ident()?) } else { None })
         };
+        let body = |this: &mut Self| {
+            Ok(if this.check(&token::OpenDelim(Delimiter::Brace)) {
+                Some(this.parse_block()?)
+            } else {
+                this.expect(&token::Semi)?;
+                None
+            })
+        };
+
+        let (ident, item_kind) = if self.eat(&token::PathSep) {
+            let (suffixes, _) = self.parse_delim_comma_seq(Delimiter::Brace, |p| {
+                Ok((p.parse_path_segment_ident()?, rename(p)?))
+            })?;
+            let deleg = DelegationMac { qself, prefix: path, suffixes, body: body(self)? };
+            (Ident::empty(), ItemKind::DelegationMac(Box::new(deleg)))
+        } else {
+            let rename = rename(self)?;
+            let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident);
+            let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body: body(self)? };
+            (ident, ItemKind::Delegation(Box::new(deleg)))
+        };
+
         let span = span.to(self.prev_token.span);
         self.psess.gated_spans.gate(sym::fn_delegation, span);
 
-        let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident);
-        let deleg = Delegation { id: DUMMY_NODE_ID, qself, path, rename, body };
-        Ok((ident, ItemKind::Delegation(Box::new(deleg))))
+        Ok((ident, item_kind))
     }
 
     fn parse_item_list<T>(
@@ -724,7 +745,7 @@
             if self.recover_doc_comment_before_brace() {
                 continue;
             }
-            self.recover_diff_marker();
+            self.recover_vcs_conflict_marker();
             match parse_item(self) {
                 Ok(None) => {
                     let mut is_unnecessary_semicolon = !items.is_empty()
@@ -850,7 +871,7 @@
 
     /// Parses `unsafe? auto? trait Foo { ... }` or `trait Foo = Bar;`.
     fn parse_item_trait(&mut self, attrs: &mut AttrVec, lo: Span) -> PResult<'a, ItemInfo> {
-        let unsafety = self.parse_unsafety(Case::Sensitive);
+        let safety = self.parse_safety(Case::Sensitive);
         // Parse optional `auto` prefix.
         let is_auto = if self.eat_keyword(kw::Auto) {
             self.psess.gated_spans.gate(sym::auto_traits, self.prev_token.span);
@@ -884,7 +905,7 @@
             if is_auto == IsAuto::Yes {
                 self.dcx().emit_err(errors::TraitAliasCannotBeAuto { span: whole_span });
             }
-            if let Unsafe::Yes(_) = unsafety {
+            if let Safety::Unsafe(_) = safety {
                 self.dcx().emit_err(errors::TraitAliasCannotBeUnsafe { span: whole_span });
             }
 
@@ -897,7 +918,7 @@
             let items = self.parse_item_list(attrs, |p| p.parse_trait_item(ForceCollect::No))?;
             Ok((
                 ident,
-                ItemKind::Trait(Box::new(Trait { is_auto, unsafety, generics, bounds, items })),
+                ItemKind::Trait(Box::new(Trait { is_auto, safety, generics, bounds, items })),
             ))
         }
     }
@@ -1056,7 +1077,11 @@
         Ok(if self.eat(&token::BinOp(token::Star)) {
             UseTreeKind::Glob
         } else {
-            UseTreeKind::Nested(self.parse_use_tree_list()?)
+            let lo = self.token.span;
+            UseTreeKind::Nested {
+                items: self.parse_use_tree_list()?,
+                span: lo.to(self.prev_token.span),
+            }
         })
     }
 
@@ -1067,7 +1092,7 @@
     /// ```
     fn parse_use_tree_list(&mut self) -> PResult<'a, ThinVec<(UseTree, ast::NodeId)>> {
         self.parse_delim_comma_seq(Delimiter::Brace, |p| {
-            p.recover_diff_marker();
+            p.recover_vcs_conflict_marker();
             Ok((p.parse_use_tree()?, DUMMY_NODE_ID))
         })
         .map(|(r, _)| r)
@@ -1154,19 +1179,19 @@
     fn parse_item_foreign_mod(
         &mut self,
         attrs: &mut AttrVec,
-        mut unsafety: Unsafe,
+        mut safety: Safety,
     ) -> PResult<'a, ItemInfo> {
         let abi = self.parse_abi(); // ABI?
-        if unsafety == Unsafe::No
+        if safety == Safety::Default
             && self.token.is_keyword(kw::Unsafe)
             && self.look_ahead(1, |t| t.kind == token::OpenDelim(Delimiter::Brace))
         {
             self.expect(&token::OpenDelim(Delimiter::Brace)).unwrap_err().emit();
-            unsafety = Unsafe::Yes(self.token.span);
+            safety = Safety::Unsafe(self.token.span);
             self.eat_keyword(kw::Unsafe);
         }
         let module = ast::ForeignMod {
-            unsafety,
+            safety,
             abi,
             items: self.parse_item_list(attrs, |p| p.parse_foreign_item(ForceCollect::No))?,
         };
@@ -1494,9 +1519,9 @@
     }
 
     fn parse_enum_variant(&mut self, span: Span) -> PResult<'a, Option<Variant>> {
-        self.recover_diff_marker();
+        self.recover_vcs_conflict_marker();
         let variant_attrs = self.parse_outer_attributes()?;
-        self.recover_diff_marker();
+        self.recover_vcs_conflict_marker();
         let help = "enum variants can be `Variant`, `Variant = <integer>`, \
                     `Variant(Type, ..., TypeN)` or `Variant { fields: Types }`";
         self.collect_tokens_trailing_token(
@@ -1536,8 +1561,8 @@
                                 this.bump(); // }
                                 err.span_label(span, "while parsing this enum");
                                 err.help(help);
-                                err.emit();
-                                (thin_vec![], Recovered::Yes)
+                                let guar = err.emit();
+                                (thin_vec![], Recovered::Yes(guar))
                             }
                         };
                     VariantData::Struct { fields, recovered: recovered.into() }
@@ -1685,6 +1710,10 @@
         Ok((class_name, ItemKind::Union(vdata, generics)))
     }
 
+    /// This function parses the fields of record structs:
+    ///
+    ///   - `struct S { ... }`
+    ///   - `enum E { Variant { ... } }`
     pub(crate) fn parse_record_struct_body(
         &mut self,
         adt_ty: &str,
@@ -1695,16 +1724,15 @@
         let mut recovered = Recovered::No;
         if self.eat(&token::OpenDelim(Delimiter::Brace)) {
             while self.token != token::CloseDelim(Delimiter::Brace) {
-                let field = self.parse_field_def(adt_ty).map_err(|e| {
-                    self.consume_block(Delimiter::Brace, ConsumeClosingDelim::No);
-                    recovered = Recovered::Yes;
-                    e
-                });
-                match field {
-                    Ok(field) => fields.push(field),
+                match self.parse_field_def(adt_ty) {
+                    Ok(field) => {
+                        fields.push(field);
+                    }
                     Err(mut err) => {
+                        self.consume_block(Delimiter::Brace, ConsumeClosingDelim::No);
                         err.span_label(ident_span, format!("while parsing this {adt_ty}"));
-                        err.emit();
+                        let guar = err.emit();
+                        recovered = Recovered::Yes(guar);
                         break;
                     }
                 }
@@ -1712,19 +1740,10 @@
             self.eat(&token::CloseDelim(Delimiter::Brace));
         } else {
             let token_str = super::token_descr(&self.token);
-            let msg = format!(
-                "expected {}`{{` after struct name, found {}",
-                if parsed_where { "" } else { "`where`, or " },
-                token_str
-            );
+            let where_str = if parsed_where { "" } else { "`where`, or " };
+            let msg = format!("expected {where_str}`{{` after struct name, found {token_str}");
             let mut err = self.dcx().struct_span_err(self.token.span, msg);
-            err.span_label(
-                self.token.span,
-                format!(
-                    "expected {}`{{` after struct name",
-                    if parsed_where { "" } else { "`where`, or " }
-                ),
-            );
+            err.span_label(self.token.span, format!("expected {where_str}`{{` after struct name",));
             return Err(err);
         }
 
@@ -1738,7 +1757,7 @@
             let attrs = p.parse_outer_attributes()?;
             p.collect_tokens_trailing_token(attrs, ForceCollect::No, |p, attrs| {
                 let mut snapshot = None;
-                if p.is_diff_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) {
+                if p.is_vcs_conflict_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) {
                     // Account for `<<<<<<<` diff markers. We can't proactively error here because
                     // that can be a valid type start, so we snapshot and reparse only we've
                     // encountered another parse error.
@@ -1749,7 +1768,7 @@
                     Ok(vis) => vis,
                     Err(err) => {
                         if let Some(ref mut snapshot) = snapshot {
-                            snapshot.recover_diff_marker();
+                            snapshot.recover_vcs_conflict_marker();
                         }
                         return Err(err);
                     }
@@ -1758,7 +1777,7 @@
                     Ok(ty) => ty,
                     Err(err) => {
                         if let Some(ref mut snapshot) = snapshot {
-                            snapshot.recover_diff_marker();
+                            snapshot.recover_vcs_conflict_marker();
                         }
                         return Err(err);
                     }
@@ -1783,9 +1802,9 @@
 
     /// Parses an element of a struct declaration.
     fn parse_field_def(&mut self, adt_ty: &str) -> PResult<'a, FieldDef> {
-        self.recover_diff_marker();
+        self.recover_vcs_conflict_marker();
         let attrs = self.parse_outer_attributes()?;
-        self.recover_diff_marker();
+        self.recover_vcs_conflict_marker();
         self.collect_tokens_trailing_token(attrs, ForceCollect::No, |this, attrs| {
             let lo = this.token.span;
             let vis = this.parse_visibility(FollowedByType::No)?;
@@ -2439,7 +2458,7 @@
         let coroutine_kind = self.parse_coroutine_kind(case);
 
         let unsafe_start_sp = self.token.span;
-        let unsafety = self.parse_unsafety(case);
+        let safety = self.parse_safety(case);
 
         let ext_start_sp = self.token.span;
         let ext = self.parse_extern(case);
@@ -2465,7 +2484,7 @@
             // `self.expected_tokens`, therefore, do not use `self.unexpected()` which doesn't
             // account for this.
             match self.expect_one_of(&[], &[]) {
-                Ok(Recovered::Yes) => {}
+                Ok(Recovered::Yes(_)) => {}
                 Ok(Recovered::No) => unreachable!(),
                 Err(mut err) => {
                     // Qualifier keywords ordering check
@@ -2477,7 +2496,7 @@
                     // We may be able to recover
                     let mut recover_constness = constness;
                     let mut recover_coroutine_kind = coroutine_kind;
-                    let mut recover_unsafety = unsafety;
+                    let mut recover_safety = safety;
                     // This will allow the machine fix to directly place the keyword in the correct place or to indicate
                     // that the keyword is already present and the second instance should be removed.
                     let wrong_kw = if self.check_keyword(kw::Const) {
@@ -2515,10 +2534,10 @@
                             }
                         }
                     } else if self.check_keyword(kw::Unsafe) {
-                        match unsafety {
-                            Unsafe::Yes(sp) => Some(WrongKw::Duplicated(sp)),
-                            Unsafe::No => {
-                                recover_unsafety = Unsafe::Yes(self.token.span);
+                        match safety {
+                            Safety::Unsafe(sp) => Some(WrongKw::Duplicated(sp)),
+                            Safety::Default => {
+                                recover_safety = Safety::Unsafe(self.token.span);
                                 Some(WrongKw::Misplaced(ext_start_sp))
                             }
                         }
@@ -2603,7 +2622,7 @@
                         err.emit();
                         return Ok(FnHeader {
                             constness: recover_constness,
-                            unsafety: recover_unsafety,
+                            safety: recover_safety,
                             coroutine_kind: recover_coroutine_kind,
                             ext,
                         });
@@ -2614,7 +2633,7 @@
             }
         }
 
-        Ok(FnHeader { constness, unsafety, coroutine_kind, ext })
+        Ok(FnHeader { constness, safety, coroutine_kind, ext })
     }
 
     /// Parses the parameter list and result type of a function declaration.
@@ -2645,7 +2664,7 @@
         }
 
         let (mut params, _) = self.parse_paren_comma_seq(|p| {
-            p.recover_diff_marker();
+            p.recover_vcs_conflict_marker();
             let snapshot = p.create_snapshot_for_diagnostic();
             let param = p.parse_param_general(req_name, first_param).or_else(|e| {
                 let guar = e.emit();
@@ -2839,7 +2858,7 @@
 
     fn is_named_param(&self) -> bool {
         let offset = match &self.token.kind {
-            token::Interpolated(nt) => match &nt.0 {
+            token::Interpolated(nt) => match &**nt {
                 token::NtPat(..) => return self.look_ahead(1, |t| t == &token::Colon),
                 _ => 0,
             },
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index 7dedf03..c218325 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -11,7 +11,6 @@
 mod ty;
 
 use crate::lexer::UnmatchedDelim;
-use ast::token::IdentIsRaw;
 pub use attr_wrapper::AttrWrapper;
 pub use diagnostics::AttemptLocalParseRecovery;
 pub(crate) use expr::ForbiddenLetReason;
@@ -21,19 +20,19 @@
 
 use core::fmt;
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Token, TokenKind};
+use rustc_ast::token::{self, Delimiter, IdentIsRaw, Nonterminal, Token, TokenKind};
 use rustc_ast::tokenstream::{AttributesData, DelimSpacing, DelimSpan, Spacing};
 use rustc_ast::tokenstream::{TokenStream, TokenTree, TokenTreeCursor};
 use rustc_ast::util::case::Case;
 use rustc_ast::{
     self as ast, AnonConst, AttrArgs, AttrArgsEq, AttrId, ByRef, Const, CoroutineKind, DelimArgs,
-    Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, StrLit, Unsafe, Visibility,
+    Expr, ExprKind, Extern, HasAttrs, HasTokens, Mutability, Recovered, Safety, StrLit, Visibility,
     VisibilityKind, DUMMY_NODE_ID,
 };
 use rustc_ast_pretty::pprust;
 use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::PResult;
-use rustc_errors::{Applicability, Diag, FatalError, MultiSpan};
+use rustc_data_structures::sync::Lrc;
+use rustc_errors::{Applicability, Diag, FatalError, MultiSpan, PResult};
 use rustc_session::parse::ParseSess;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
@@ -108,7 +107,7 @@
 macro_rules! maybe_whole {
     ($p:expr, $constructor:ident, |$x:ident| $e:expr) => {
         if let token::Interpolated(nt) = &$p.token.kind
-            && let token::$constructor(x) = &nt.0
+            && let token::$constructor(x) = &**nt
         {
             #[allow(unused_mut)]
             let mut $x = x.clone();
@@ -126,7 +125,7 @@
             && $self.may_recover()
             && $self.look_ahead(1, |t| t == &token::PathSep)
             && let token::Interpolated(nt) = &$self.token.kind
-            && let token::NtTy(ty) = &nt.0
+            && let token::NtTy(ty) = &**nt
         {
             let ty = ty.clone();
             $self.bump();
@@ -374,19 +373,6 @@
     No,
 }
 
-/// Whether a function performed recovery
-#[derive(Copy, Clone, Debug)]
-pub enum Recovered {
-    No,
-    Yes,
-}
-
-impl From<Recovered> for bool {
-    fn from(r: Recovered) -> bool {
-        matches!(r, Recovered::Yes)
-    }
-}
-
 #[derive(Copy, Clone, Debug)]
 pub enum Trailing {
     No,
@@ -421,7 +407,9 @@
         (Some(TokenDescription::Keyword), _) => Some("keyword"),
         (Some(TokenDescription::ReservedKeyword), _) => Some("reserved keyword"),
         (Some(TokenDescription::DocComment), _) => Some("doc comment"),
-        (None, TokenKind::Interpolated(node)) => Some(node.0.descr()),
+        (None, TokenKind::NtIdent(..)) => Some("identifier"),
+        (None, TokenKind::NtLifetime(..)) => Some("lifetime"),
+        (None, TokenKind::Interpolated(node)) => Some(node.descr()),
         (None, _) => None,
     };
 
@@ -722,7 +710,7 @@
     fn check_inline_const(&self, dist: usize) -> bool {
         self.is_keyword_ahead(dist, &[kw::Const])
             && self.look_ahead(dist + 1, |t| match &t.kind {
-                token::Interpolated(nt) => matches!(&nt.0, token::NtBlock(..)),
+                token::Interpolated(nt) => matches!(&**nt, token::NtBlock(..)),
                 token::OpenDelim(Delimiter::Brace) => true,
                 _ => false,
             })
@@ -856,9 +844,9 @@
                         Ok(Recovered::No) => {
                             self.current_closure.take();
                         }
-                        Ok(Recovered::Yes) => {
+                        Ok(Recovered::Yes(guar)) => {
                             self.current_closure.take();
-                            recovered = Recovered::Yes;
+                            recovered = Recovered::Yes(guar);
                             break;
                         }
                         Err(mut expect_err) => {
@@ -1229,12 +1217,12 @@
         }
     }
 
-    /// Parses unsafety: `unsafe` or nothing.
-    fn parse_unsafety(&mut self, case: Case) -> Unsafe {
+    /// Parses fn unsafety: `unsafe`, `safe` or nothing.
+    fn parse_safety(&mut self, case: Case) -> Safety {
         if self.eat_keyword_case(kw::Unsafe, case) {
-            Unsafe::Yes(self.prev_token.uninterpolated_span())
+            Safety::Unsafe(self.prev_token.uninterpolated_span())
         } else {
-            Unsafe::No
+            Safety::Default
         }
     }
 
@@ -1645,19 +1633,11 @@
 
 // Metavar captures of various kinds.
 #[derive(Clone, Debug)]
-pub enum ParseNtResult<NtType> {
+pub enum ParseNtResult {
     Tt(TokenTree),
-    Nt(NtType),
-}
+    Ident(Ident, IdentIsRaw),
+    Lifetime(Ident),
 
-impl<T> ParseNtResult<T> {
-    pub fn map_nt<F, U>(self, mut f: F) -> ParseNtResult<U>
-    where
-        F: FnMut(T) -> U,
-    {
-        match self {
-            ParseNtResult::Tt(tt) => ParseNtResult::Tt(tt),
-            ParseNtResult::Nt(nt) => ParseNtResult::Nt(f(nt)),
-        }
-    }
+    /// This case will eventually be removed, along with `Token::Interpolate`.
+    Nt(Lrc<Nonterminal>),
 }
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 73b1735..619c4c6 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -1,7 +1,8 @@
 use rustc_ast::ptr::P;
-use rustc_ast::token::{self, Delimiter, Nonterminal, Nonterminal::*, NonterminalKind, Token};
+use rustc_ast::token::{self, Delimiter, Nonterminal::*, NonterminalKind, Token};
 use rustc_ast::HasTokens;
 use rustc_ast_pretty::pprust;
+use rustc_data_structures::sync::Lrc;
 use rustc_errors::PResult;
 use rustc_span::symbol::{kw, Ident};
 
@@ -24,50 +25,59 @@
                 | NtPat(_)
                 | NtExpr(_)
                 | NtTy(_)
-                | NtIdent(..)
                 | NtLiteral(_) // `true`, `false`
                 | NtMeta(_)
                 | NtPath(_) => true,
 
                 NtItem(_)
                 | NtBlock(_)
-                | NtVis(_)
-                | NtLifetime(_) => false,
+                | NtVis(_) => false,
             }
         }
 
         match kind {
-            NonterminalKind::Expr => {
+            NonterminalKind::Expr2021 => {
                 token.can_begin_expr()
                 // This exception is here for backwards compatibility.
                 && !token.is_keyword(kw::Let)
                 // This exception is here for backwards compatibility.
                 && !token.is_keyword(kw::Const)
             }
+            NonterminalKind::Expr => {
+                token.can_begin_expr()
+                // This exception is here for backwards compatibility.
+                && !token.is_keyword(kw::Let)
+                && (token.span.edition().at_least_rust_2024() || !token.is_keyword(kw::Const))
+            }
             NonterminalKind::Ty => token.can_begin_type(),
             NonterminalKind::Ident => get_macro_ident(token).is_some(),
             NonterminalKind::Literal => token.can_begin_literal_maybe_minus(),
             NonterminalKind::Vis => match token.kind {
                 // The follow-set of :vis + "priv" keyword + interpolated
-                token::Comma | token::Ident(..) | token::Interpolated(_) => true,
+                token::Comma
+                | token::Ident(..)
+                | token::NtIdent(..)
+                | token::NtLifetime(..)
+                | token::Interpolated(_) => true,
                 _ => token.can_begin_type(),
             },
             NonterminalKind::Block => match &token.kind {
                 token::OpenDelim(Delimiter::Brace) => true,
-                token::Interpolated(nt) => match &nt.0 {
-                    NtBlock(_) | NtLifetime(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
-                    NtItem(_) | NtPat(_) | NtTy(_) | NtIdent(..) | NtMeta(_) | NtPath(_)
-                    | NtVis(_) => false,
+                token::NtLifetime(..) => true,
+                token::Interpolated(nt) => match &**nt {
+                    NtBlock(_) | NtStmt(_) | NtExpr(_) | NtLiteral(_) => true,
+                    NtItem(_) | NtPat(_) | NtTy(_) | NtMeta(_) | NtPath(_) | NtVis(_) => false,
                 },
                 _ => false,
             },
             NonterminalKind::Path | NonterminalKind::Meta => match &token.kind {
-                token::PathSep | token::Ident(..) => true,
-                token::Interpolated(nt) => may_be_ident(&nt.0),
+                token::PathSep | token::Ident(..) | token::NtIdent(..) => true,
+                token::Interpolated(nt) => may_be_ident(nt),
                 _ => false,
             },
             NonterminalKind::PatParam { .. } | NonterminalKind::PatWithOr => match &token.kind {
-                token::Ident(..) |                          // box, ref, mut, and other identifiers (can stricten)
+                // box, ref, mut, and other identifiers (can stricten)
+                token::Ident(..) | token::NtIdent(..) |
                 token::OpenDelim(Delimiter::Parenthesis) |  // tuple pattern
                 token::OpenDelim(Delimiter::Bracket) |      // slice pattern
                 token::BinOp(token::And) |                  // reference
@@ -81,14 +91,11 @@
                 token::BinOp(token::Shl) => true,           // path (double UFCS)
                 // leading vert `|` or-pattern
                 token::BinOp(token::Or) => matches!(kind, NonterminalKind::PatWithOr),
-                token::Interpolated(nt) => may_be_ident(&nt.0),
+                token::Interpolated(nt) => may_be_ident(nt),
                 _ => false,
             },
             NonterminalKind::Lifetime => match &token.kind {
-                token::Lifetime(_) => true,
-                token::Interpolated(nt) => {
-                    matches!(&nt.0, NtLifetime(_))
-                }
+                token::Lifetime(_) | token::NtLifetime(..) => true,
                 _ => false,
             },
             NonterminalKind::TT | NonterminalKind::Item | NonterminalKind::Stmt => {
@@ -100,10 +107,7 @@
     /// Parse a non-terminal (e.g. MBE `:pat` or `:ident`). Inlined because there is only one call
     /// site.
     #[inline]
-    pub fn parse_nonterminal(
-        &mut self,
-        kind: NonterminalKind,
-    ) -> PResult<'a, ParseNtResult<Nonterminal>> {
+    pub fn parse_nonterminal(&mut self, kind: NonterminalKind) -> PResult<'a, ParseNtResult> {
         // A `macro_rules!` invocation may pass a captured item/expr to a proc-macro,
         // which requires having captured tokens available. Since we cannot determine
         // in advance whether or not a proc-macro will be (transitively) invoked,
@@ -145,7 +149,9 @@
                 })?)
             }
 
-            NonterminalKind::Expr => NtExpr(self.parse_expr_force_collect()?),
+            NonterminalKind::Expr | NonterminalKind::Expr2021 => {
+                NtExpr(self.parse_expr_force_collect()?)
+            }
             NonterminalKind::Literal => {
                 // The `:literal` matcher does not support attributes
                 NtLiteral(self.collect_tokens_no_attrs(|this| this.parse_literal_maybe_minus())?)
@@ -156,15 +162,16 @@
             }
 
             // this could be handled like a token, since it is one
-            NonterminalKind::Ident if let Some((ident, is_raw)) = get_macro_ident(&self.token) => {
-                self.bump();
-                NtIdent(ident, is_raw)
-            }
             NonterminalKind::Ident => {
-                return Err(self.dcx().create_err(UnexpectedNonterminal::Ident {
-                    span: self.token.span,
-                    token: self.token.clone(),
-                }));
+                return if let Some((ident, is_raw)) = get_macro_ident(&self.token) {
+                    self.bump();
+                    Ok(ParseNtResult::Ident(ident, is_raw))
+                } else {
+                    Err(self.dcx().create_err(UnexpectedNonterminal::Ident {
+                        span: self.token.span,
+                        token: self.token.clone(),
+                    }))
+                };
             }
             NonterminalKind::Path => {
                 NtPath(P(self.collect_tokens_no_attrs(|this| this.parse_path(PathStyle::Type))?))
@@ -175,14 +182,14 @@
                     .collect_tokens_no_attrs(|this| this.parse_visibility(FollowedByType::Yes))?))
             }
             NonterminalKind::Lifetime => {
-                if self.check_lifetime() {
-                    NtLifetime(self.expect_lifetime().ident)
+                return if self.check_lifetime() {
+                    Ok(ParseNtResult::Lifetime(self.expect_lifetime().ident))
                 } else {
-                    return Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime {
+                    Err(self.dcx().create_err(UnexpectedNonterminal::Lifetime {
                         span: self.token.span,
                         token: self.token.clone(),
-                    }));
-                }
+                    }))
+                };
             }
         };
 
@@ -196,7 +203,7 @@
             );
         }
 
-        Ok(ParseNtResult::Nt(nt))
+        Ok(ParseNtResult::Nt(Lrc::new(nt)))
     }
 }
 
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 78d3d01..8af415f 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -757,7 +757,7 @@
 
         // Make sure we don't allow e.g. `let mut $p;` where `$p:pat`.
         if let token::Interpolated(nt) = &self.token.kind {
-            if let token::NtPat(..) = &nt.0 {
+            if let token::NtPat(..) = &**nt {
                 self.expected_ident_found_err().emit();
             }
         }
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index b97ec8c..d845e8a 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -95,12 +95,15 @@
             debug!("parse_qpath: (decrement) count={:?}", self.unmatched_angle_bracket_count);
         }
 
-        if !self.recover_colon_before_qpath_proj() {
+        let is_import_coupler = self.is_import_coupler();
+        if !is_import_coupler && !self.recover_colon_before_qpath_proj() {
             self.expect(&token::PathSep)?;
         }
 
         let qself = P(QSelf { ty, path_span, position: path.segments.len() });
-        self.parse_path_segments(&mut path.segments, style, None)?;
+        if !is_import_coupler {
+            self.parse_path_segments(&mut path.segments, style, None)?;
+        }
 
         Ok((
             qself,
@@ -160,7 +163,7 @@
         style: PathStyle,
         ty_generics: Option<&Generics>,
     ) -> PResult<'a, Path> {
-        let reject_generics_if_mod_style = |parser: &Parser<'_>, path: &Path| {
+        let reject_generics_if_mod_style = |parser: &Parser<'_>, path: Path| {
             // Ensure generic arguments don't end up in attribute paths, such as:
             //
             //     macro_rules! m {
@@ -178,21 +181,26 @@
                     .map(|arg| arg.span())
                     .collect::<Vec<_>>();
                 parser.dcx().emit_err(errors::GenericsInPath { span });
+                // Ignore these arguments to prevent unexpected behaviors.
+                let segments = path
+                    .segments
+                    .iter()
+                    .map(|segment| PathSegment { ident: segment.ident, id: segment.id, args: None })
+                    .collect();
+                Path { segments, ..path }
+            } else {
+                path
             }
         };
 
-        maybe_whole!(self, NtPath, |path| {
-            reject_generics_if_mod_style(self, &path);
-            path.into_inner()
-        });
+        maybe_whole!(self, NtPath, |path| reject_generics_if_mod_style(self, path.into_inner()));
 
         if let token::Interpolated(nt) = &self.token.kind {
-            if let token::NtTy(ty) = &nt.0 {
+            if let token::NtTy(ty) = &**nt {
                 if let ast::TyKind::Path(None, path) = &ty.kind {
                     let path = path.clone();
                     self.bump();
-                    reject_generics_if_mod_style(self, &path);
-                    return Ok(path);
+                    return Ok(reject_generics_if_mod_style(self, path));
                 }
             }
         }
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index 6601011..7424fbe 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -11,14 +11,13 @@
 use crate::maybe_whole;
 
 use crate::errors::MalformedLoopLabel;
-use crate::parser::Recovered;
 use ast::Label;
 use rustc_ast as ast;
 use rustc_ast::ptr::P;
 use rustc_ast::token::{self, Delimiter, TokenKind};
 use rustc_ast::util::classify;
 use rustc_ast::{AttrStyle, AttrVec, LocalKind, MacCall, MacCallStmt, MacStmtStyle};
-use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt};
+use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Recovered, Stmt};
 use rustc_ast::{StmtKind, DUMMY_NODE_ID};
 use rustc_errors::{Applicability, Diag, PResult};
 use rustc_span::symbol::{kw, sym, Ident};
@@ -568,7 +567,7 @@
             if self.token == token::Eof {
                 break;
             }
-            if self.is_diff_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) {
+            if self.is_vcs_conflict_marker(&TokenKind::BinOp(token::Shl), &TokenKind::Lt) {
                 // Account for `<<<<<<<` diff markers. We can't proactively error here because
                 // that can be a valid path start, so we snapshot and reparse only we've
                 // encountered another parse error.
@@ -577,7 +576,7 @@
             let stmt = match self.parse_full_stmt(recover) {
                 Err(mut err) if recover.yes() => {
                     if let Some(ref mut snapshot) = snapshot {
-                        snapshot.recover_diff_marker();
+                        snapshot.recover_vcs_conflict_marker();
                     }
                     if self.token == token::Colon {
                         // if a previous and next token of the current one is
@@ -675,11 +674,8 @@
                 let replace_with_err = 'break_recover: {
                     match expect_result {
                         Ok(Recovered::No) => None,
-                        Ok(Recovered::Yes) => {
+                        Ok(Recovered::Yes(guar)) => {
                             // Skip type error to avoid extra errors.
-                            let guar = self
-                                .dcx()
-                                .span_delayed_bug(self.prev_token.span, "expected `;` or `}`");
                             Some(guar)
                         }
                         Err(e) => {
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 7096b20..2df8f58 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -590,7 +590,7 @@
             tokens: None,
         };
         let span_start = self.token.span;
-        let ast::FnHeader { ext, unsafety, constness, coroutine_kind } =
+        let ast::FnHeader { ext, safety, constness, coroutine_kind } =
             self.parse_fn_front_matter(&inherited_vis, Case::Sensitive)?;
         if self.may_recover() && self.token.kind == TokenKind::Lt {
             self.recover_fn_ptr_with_generics(lo, &mut params, param_insertion_point)?;
@@ -608,7 +608,7 @@
         }
         // FIXME(gen_blocks): emit a similar error for `gen fn()`
         let decl_span = span_start.to(self.token.span);
-        Ok(TyKind::BareFn(P(BareFnTy { ext, unsafety, generic_params: params, decl, decl_span })))
+        Ok(TyKind::BareFn(P(BareFnTy { ext, safety, generic_params: params, decl, decl_span })))
     }
 
     /// Recover from function pointer types with a generic parameter list (e.g. `fn<'a>(&'a str)`).
@@ -675,8 +675,8 @@
         let precise_capturing = if self.eat_keyword(kw::Use) {
             let use_span = self.prev_token.span;
             self.psess.gated_spans.gate(sym::precise_capturing, use_span);
-            let args = self.parse_precise_capturing_args()?;
-            Some(P((args, use_span)))
+            let (args, args_span) = self.parse_precise_capturing_args()?;
+            Some(P((args, use_span.to(args_span))))
         } else {
             None
         };
@@ -689,32 +689,34 @@
         Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds, precise_capturing))
     }
 
-    fn parse_precise_capturing_args(&mut self) -> PResult<'a, ThinVec<PreciseCapturingArg>> {
-        Ok(self
-            .parse_unspanned_seq(
-                &TokenKind::Lt,
-                &TokenKind::Gt,
-                SeqSep::trailing_allowed(token::Comma),
-                |self_| {
-                    if self_.check_keyword(kw::SelfUpper) {
-                        self_.bump();
-                        Ok(PreciseCapturingArg::Arg(
-                            ast::Path::from_ident(self_.prev_token.ident().unwrap().0),
-                            DUMMY_NODE_ID,
-                        ))
-                    } else if self_.check_ident() {
-                        Ok(PreciseCapturingArg::Arg(
-                            ast::Path::from_ident(self_.parse_ident()?),
-                            DUMMY_NODE_ID,
-                        ))
-                    } else if self_.check_lifetime() {
-                        Ok(PreciseCapturingArg::Lifetime(self_.expect_lifetime()))
-                    } else {
-                        self_.unexpected_any()
-                    }
-                },
-            )?
-            .0)
+    fn parse_precise_capturing_args(
+        &mut self,
+    ) -> PResult<'a, (ThinVec<PreciseCapturingArg>, Span)> {
+        let lo = self.token.span;
+        let (args, _) = self.parse_unspanned_seq(
+            &TokenKind::Lt,
+            &TokenKind::Gt,
+            SeqSep::trailing_allowed(token::Comma),
+            |self_| {
+                if self_.check_keyword(kw::SelfUpper) {
+                    self_.bump();
+                    Ok(PreciseCapturingArg::Arg(
+                        ast::Path::from_ident(self_.prev_token.ident().unwrap().0),
+                        DUMMY_NODE_ID,
+                    ))
+                } else if self_.check_ident() {
+                    Ok(PreciseCapturingArg::Arg(
+                        ast::Path::from_ident(self_.parse_ident()?),
+                        DUMMY_NODE_ID,
+                    ))
+                } else if self_.check_lifetime() {
+                    Ok(PreciseCapturingArg::Lifetime(self_.expect_lifetime()))
+                } else {
+                    self_.unexpected_any()
+                }
+            },
+        )?;
+        Ok((args, lo.to(self.prev_token.span)))
     }
 
     /// Is a `dyn B0 + ... + Bn` type allowed here?
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index f88edf2..b91ef1a 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -10,6 +10,7 @@
 use rustc_feature::{AttributeTemplate, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
 use rustc_session::errors::report_lit_error;
 use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT;
+use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::parse::ParseSess;
 use rustc_span::{sym, Span, Symbol};
 
@@ -176,37 +177,26 @@
     };
 
     let error_msg = format!("malformed `{name}` attribute input");
-    let mut msg = "attribute must be of the form ".to_owned();
     let mut suggestions = vec![];
-    let mut first = true;
     let inner = if style == ast::AttrStyle::Inner { "!" } else { "" };
     if template.word {
-        first = false;
-        let code = format!("#{inner}[{name}]");
-        msg.push_str(&format!("`{code}`"));
-        suggestions.push(code);
+        suggestions.push(format!("#{inner}[{name}]"));
     }
     if let Some(descr) = template.list {
-        if !first {
-            msg.push_str(" or ");
-        }
-        first = false;
-        let code = format!("#{inner}[{name}({descr})]");
-        msg.push_str(&format!("`{code}`"));
-        suggestions.push(code);
+        suggestions.push(format!("#{inner}[{name}({descr})]"));
     }
     if let Some(descr) = template.name_value_str {
-        if !first {
-            msg.push_str(" or ");
-        }
-        let code = format!("#{inner}[{name} = \"{descr}\"]");
-        msg.push_str(&format!("`{code}`"));
-        suggestions.push(code);
+        suggestions.push(format!("#{inner}[{name} = \"{descr}\"]"));
     }
-    suggestions.sort();
     if should_warn(name) {
-        psess.buffer_lint(ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, msg);
+        psess.buffer_lint(
+            ILL_FORMED_ATTRIBUTE_INPUT,
+            span,
+            ast::CRATE_NODE_ID,
+            BuiltinLintDiag::IllFormedAttributeInput { suggestions: suggestions.clone() },
+        );
     } else {
+        suggestions.sort();
         psess
             .dcx
             .struct_span_err(span, error_msg)
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index 9d58d30..d850644 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -52,16 +52,16 @@
 passes_both_ffi_const_and_pure =
     `#[ffi_const]` function cannot be `#[ffi_pure]`
 
-passes_break_inside_async_block =
-    `{$name}` inside of an `async` block
-    .label = cannot `{$name}` inside of an `async` block
-    .async_block_label = enclosing `async` block
-
 passes_break_inside_closure =
     `{$name}` inside of a closure
     .label = cannot `{$name}` inside of a closure
     .closure_label = enclosing closure
 
+passes_break_inside_coroutine =
+    `{$name}` inside `{$kind}` {$source}
+    .label = cannot `{$name}` inside `{$kind}` {$source}
+    .coroutine_label = enclosing `{$kind}` {$source}
+
 passes_break_non_loop =
     `break` with value from a `{$kind}` loop
     .label = can only break with a value inside `loop` or breakable block
@@ -341,7 +341,7 @@
     feature `{$implied_by}` implying `{$feature}` does not exist
 
 passes_incorrect_do_not_recommend_location =
-    `#[do_not_recommend]` can only be placed on trait implementations
+    `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
 
 passes_incorrect_meta_item = expected a quoted string literal
 passes_incorrect_meta_item_suggestion = consider surrounding this with quotes
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index e60aa27..1924533 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -17,7 +17,7 @@
 use rustc_hir::{
     self, FnSig, ForeignItem, HirId, Item, ItemKind, TraitItem, CRATE_HIR_ID, CRATE_OWNER_ID,
 };
-use rustc_hir::{MethodKind, Target, Unsafety};
+use rustc_hir::{MethodKind, Safety, Target};
 use rustc_macros::LintDiagnostic;
 use rustc_middle::bug;
 use rustc_middle::hir::nested_filter;
@@ -42,12 +42,9 @@
 
 #[derive(LintDiagnostic)]
 #[diag(passes_diagnostic_diagnostic_on_unimplemented_only_for_traits)]
-pub struct DiagnosticOnUnimplementedOnlyForTraits;
+struct DiagnosticOnUnimplementedOnlyForTraits;
 
-pub(crate) fn target_from_impl_item<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    impl_item: &hir::ImplItem<'_>,
-) -> Target {
+fn target_from_impl_item<'tcx>(tcx: TyCtxt<'tcx>, impl_item: &hir::ImplItem<'_>) -> Target {
     match impl_item.kind {
         hir::ImplItemKind::Const(..) => Target::AssocConst,
         hir::ImplItemKind::Fn(..) => {
@@ -99,7 +96,7 @@
 }
 
 impl<'tcx> CheckAttrVisitor<'tcx> {
-    pub fn dcx(&self) -> &'tcx DiagCtxt {
+    fn dcx(&self) -> &'tcx DiagCtxt {
         self.tcx.dcx()
     }
 
@@ -116,92 +113,96 @@
         let mut seen = FxHashMap::default();
         let attrs = self.tcx.hir().attrs(hir_id);
         for attr in attrs {
-            if attr.path_matches(&[sym::diagnostic, sym::on_unimplemented]) {
-                self.check_diagnostic_on_unimplemented(attr.span, hir_id, target);
-            }
-            match attr.name_or_empty() {
-                sym::do_not_recommend => self.check_do_not_recommend(attr.span, target),
-                sym::inline => self.check_inline(hir_id, attr, span, target),
-                sym::coverage => self.check_coverage(hir_id, attr, span, target),
-                sym::non_exhaustive => self.check_non_exhaustive(hir_id, attr, span, target),
-                sym::marker => self.check_marker(hir_id, attr, span, target),
-                sym::target_feature => self.check_target_feature(hir_id, attr, span, target, attrs),
-                sym::thread_local => self.check_thread_local(attr, span, target),
-                sym::track_caller => {
+            match attr.path().as_slice() {
+                [sym::diagnostic, sym::do_not_recommend] => {
+                    self.check_do_not_recommend(attr.span, hir_id, target)
+                }
+                [sym::diagnostic, sym::on_unimplemented] => {
+                    self.check_diagnostic_on_unimplemented(attr.span, hir_id, target)
+                }
+                [sym::inline] => self.check_inline(hir_id, attr, span, target),
+                [sym::coverage] => self.check_coverage(hir_id, attr, span, target),
+                [sym::non_exhaustive] => self.check_non_exhaustive(hir_id, attr, span, target),
+                [sym::marker] => self.check_marker(hir_id, attr, span, target),
+                [sym::target_feature] => {
+                    self.check_target_feature(hir_id, attr, span, target, attrs)
+                }
+                [sym::thread_local] => self.check_thread_local(attr, span, target),
+                [sym::track_caller] => {
                     self.check_track_caller(hir_id, attr.span, attrs, span, target)
                 }
-                sym::doc => self.check_doc_attrs(
+                [sym::doc] => self.check_doc_attrs(
                     attr,
                     hir_id,
                     target,
                     &mut specified_inline,
                     &mut doc_aliases,
                 ),
-                sym::no_link => self.check_no_link(hir_id, attr, span, target),
-                sym::export_name => self.check_export_name(hir_id, attr, span, target),
-                sym::rustc_layout_scalar_valid_range_start
-                | sym::rustc_layout_scalar_valid_range_end => {
+                [sym::no_link] => self.check_no_link(hir_id, attr, span, target),
+                [sym::export_name] => self.check_export_name(hir_id, attr, span, target),
+                [sym::rustc_layout_scalar_valid_range_start]
+                | [sym::rustc_layout_scalar_valid_range_end] => {
                     self.check_rustc_layout_scalar_valid_range(attr, span, target)
                 }
-                sym::allow_internal_unstable => {
+                [sym::allow_internal_unstable] => {
                     self.check_allow_internal_unstable(hir_id, attr, span, target, attrs)
                 }
-                sym::debugger_visualizer => self.check_debugger_visualizer(attr, target),
-                sym::rustc_allow_const_fn_unstable => {
+                [sym::debugger_visualizer] => self.check_debugger_visualizer(attr, target),
+                [sym::rustc_allow_const_fn_unstable] => {
                     self.check_rustc_allow_const_fn_unstable(hir_id, attr, span, target)
                 }
-                sym::rustc_std_internal_symbol => {
+                [sym::rustc_std_internal_symbol] => {
                     self.check_rustc_std_internal_symbol(attr, span, target)
                 }
-                sym::naked => self.check_naked(hir_id, attr, span, target),
-                sym::rustc_never_returns_null_ptr => {
+                [sym::naked] => self.check_naked(hir_id, attr, span, target),
+                [sym::rustc_never_returns_null_ptr] => {
                     self.check_applied_to_fn_or_method(hir_id, attr, span, target)
                 }
-                sym::rustc_legacy_const_generics => {
+                [sym::rustc_legacy_const_generics] => {
                     self.check_rustc_legacy_const_generics(hir_id, attr, span, target, item)
                 }
-                sym::rustc_lint_query_instability => {
+                [sym::rustc_lint_query_instability] => {
                     self.check_rustc_lint_query_instability(hir_id, attr, span, target)
                 }
-                sym::rustc_lint_diagnostics => {
+                [sym::rustc_lint_diagnostics] => {
                     self.check_rustc_lint_diagnostics(hir_id, attr, span, target)
                 }
-                sym::rustc_lint_opt_ty => self.check_rustc_lint_opt_ty(attr, span, target),
-                sym::rustc_lint_opt_deny_field_access => {
+                [sym::rustc_lint_opt_ty] => self.check_rustc_lint_opt_ty(attr, span, target),
+                [sym::rustc_lint_opt_deny_field_access] => {
                     self.check_rustc_lint_opt_deny_field_access(attr, span, target)
                 }
-                sym::rustc_clean
-                | sym::rustc_dirty
-                | sym::rustc_if_this_changed
-                | sym::rustc_then_this_would_need => self.check_rustc_dirty_clean(attr),
-                sym::rustc_coinductive
-                | sym::rustc_must_implement_one_of
-                | sym::rustc_deny_explicit_impl
-                | sym::const_trait => self.check_must_be_applied_to_trait(attr, span, target),
-                sym::cmse_nonsecure_entry => {
+                [sym::rustc_clean]
+                | [sym::rustc_dirty]
+                | [sym::rustc_if_this_changed]
+                | [sym::rustc_then_this_would_need] => self.check_rustc_dirty_clean(attr),
+                [sym::rustc_coinductive]
+                | [sym::rustc_must_implement_one_of]
+                | [sym::rustc_deny_explicit_impl]
+                | [sym::const_trait] => self.check_must_be_applied_to_trait(attr, span, target),
+                [sym::cmse_nonsecure_entry] => {
                     self.check_cmse_nonsecure_entry(hir_id, attr, span, target)
                 }
-                sym::collapse_debuginfo => self.check_collapse_debuginfo(attr, span, target),
-                sym::must_not_suspend => self.check_must_not_suspend(attr, span, target),
-                sym::must_use => self.check_must_use(hir_id, attr, target),
-                sym::rustc_pass_by_value => self.check_pass_by_value(attr, span, target),
-                sym::rustc_allow_incoherent_impl => {
+                [sym::collapse_debuginfo] => self.check_collapse_debuginfo(attr, span, target),
+                [sym::must_not_suspend] => self.check_must_not_suspend(attr, span, target),
+                [sym::must_use] => self.check_must_use(hir_id, attr, target),
+                [sym::rustc_pass_by_value] => self.check_pass_by_value(attr, span, target),
+                [sym::rustc_allow_incoherent_impl] => {
                     self.check_allow_incoherent_impl(attr, span, target)
                 }
-                sym::rustc_has_incoherent_inherent_impls => {
+                [sym::rustc_has_incoherent_inherent_impls] => {
                     self.check_has_incoherent_inherent_impls(attr, span, target)
                 }
-                sym::ffi_pure => self.check_ffi_pure(attr.span, attrs, target),
-                sym::ffi_const => self.check_ffi_const(attr.span, target),
-                sym::rustc_const_unstable
-                | sym::rustc_const_stable
-                | sym::unstable
-                | sym::stable
-                | sym::rustc_allowed_through_unstable_modules
-                | sym::rustc_promotable => self.check_stability_promotable(attr, target),
-                sym::link_ordinal => self.check_link_ordinal(attr, span, target),
-                sym::rustc_confusables => self.check_confusables(attr, target),
-                sym::rustc_safe_intrinsic => {
+                [sym::ffi_pure] => self.check_ffi_pure(attr.span, attrs, target),
+                [sym::ffi_const] => self.check_ffi_const(attr.span, target),
+                [sym::rustc_const_unstable]
+                | [sym::rustc_const_stable]
+                | [sym::unstable]
+                | [sym::stable]
+                | [sym::rustc_allowed_through_unstable_modules]
+                | [sym::rustc_promotable] => self.check_stability_promotable(attr, target),
+                [sym::link_ordinal] => self.check_link_ordinal(attr, span, target),
+                [sym::rustc_confusables] => self.check_confusables(attr, target),
+                [sym::rustc_safe_intrinsic] => {
                     self.check_rustc_safe_intrinsic(hir_id, attr, span, target)
                 }
                 _ => true,
@@ -293,18 +294,26 @@
         );
     }
 
-    /// Checks if `#[do_not_recommend]` is applied on a trait impl.
-    fn check_do_not_recommend(&self, attr_span: Span, target: Target) -> bool {
-        if let Target::Impl = target {
-            true
-        } else {
-            self.dcx().emit_err(errors::IncorrectDoNotRecommendLocation { span: attr_span });
-            false
+    /// Checks if `#[diagnostic::do_not_recommend]` is applied on a trait impl.
+    fn check_do_not_recommend(&self, attr_span: Span, hir_id: HirId, target: Target) -> bool {
+        if !matches!(target, Target::Impl) {
+            self.tcx.emit_node_span_lint(
+                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                hir_id,
+                attr_span,
+                errors::IncorrectDoNotRecommendLocation,
+            );
         }
+        true
     }
 
     /// Checks if `#[diagnostic::on_unimplemented]` is applied to a trait definition
-    fn check_diagnostic_on_unimplemented(&self, attr_span: Span, hir_id: HirId, target: Target) {
+    fn check_diagnostic_on_unimplemented(
+        &self,
+        attr_span: Span,
+        hir_id: HirId,
+        target: Target,
+    ) -> bool {
         if !matches!(target, Target::Trait) {
             self.tcx.emit_node_span_lint(
                 UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
@@ -313,6 +322,7 @@
                 DiagnosticOnUnimplementedOnlyForTraits,
             );
         }
+        true
     }
 
     /// Checks if an `#[inline]` is applied to a function or a closure. Returns `true` if valid.
@@ -2335,7 +2345,7 @@
             }),
             token_stream,
             false,
-            Unsafety::Normal,
+            Safety::Safe,
             Abi::Rust,
         );
 
@@ -2362,7 +2372,7 @@
                             cause.span = ty.span;
                         }
                     }
-                    TypeError::UnsafetyMismatch(_) => {
+                    TypeError::SafetyMismatch(_) => {
                         // FIXME: Would be nice if we had a span here..
                     }
                     TypeError::AbiMismatch(_) => {
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 65cad82..1805527 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -17,12 +17,9 @@
 use crate::check_attr::ProcMacroKind;
 use crate::lang_items::Duplicate;
 
-#[derive(Diagnostic)]
+#[derive(LintDiagnostic)]
 #[diag(passes_incorrect_do_not_recommend_location)]
-pub struct IncorrectDoNotRecommendLocation {
-    #[primary_span]
-    pub span: Span,
-}
+pub struct IncorrectDoNotRecommendLocation;
 
 #[derive(LintDiagnostic)]
 #[diag(passes_outer_crate_level_attr)]
@@ -1086,14 +1083,16 @@
 }
 
 #[derive(Diagnostic)]
-#[diag(passes_break_inside_async_block, code = E0267)]
-pub struct BreakInsideAsyncBlock<'a> {
+#[diag(passes_break_inside_coroutine, code = E0267)]
+pub struct BreakInsideCoroutine<'a> {
     #[primary_span]
     #[label]
     pub span: Span,
-    #[label(passes_async_block_label)]
-    pub closure_span: Span,
+    #[label(passes_coroutine_label)]
+    pub coroutine_span: Span,
     pub name: &'a str,
+    pub kind: &'a str,
+    pub source: &'a str,
 }
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index d7664d1..a980d5d 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -522,7 +522,8 @@
                 Impl,
                 MacCall,
                 MacroDef,
-                Delegation
+                Delegation,
+                DelegationMac
             ]
         );
         ast_visit::walk_item(self, i)
@@ -650,7 +651,7 @@
     fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) {
         record_variants!(
             (self, i, i.kind, Id::None, ast, AssocItem, AssocItemKind),
-            [Const, Fn, Type, MacCall, Delegation]
+            [Const, Fn, Type, MacCall, Delegation, DelegationMac]
         );
         ast_visit::walk_assoc_item(self, i, ctxt);
     }
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index c1da892..b3722e9 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -149,8 +149,9 @@
                 }
             };
 
-            // When there's a duplicate lang item, something went very wrong and there's no value in recovering or doing anything.
-            // Give the user the one message to let them debug the mess they created and then wish them farewell.
+            // When there's a duplicate lang item, something went very wrong and there's no value
+            // in recovering or doing anything. Give the user the one message to let them debug the
+            // mess they created and then wish them farewell.
             self.tcx.dcx().emit_fatal(DuplicateLangItem {
                 local_span: item_span,
                 lang_item_name,
@@ -285,7 +286,9 @@
             ast::ItemKind::TraitAlias(_, _) => Target::TraitAlias,
             ast::ItemKind::Impl(_) => Target::Impl,
             ast::ItemKind::MacroDef(_) => Target::MacroDef,
-            ast::ItemKind::MacCall(_) => unreachable!("macros should have been expanded"),
+            ast::ItemKind::MacCall(_) | ast::ItemKind::DelegationMac(_) => {
+                unreachable!("macros should have been expanded")
+            }
         };
 
         self.check_for_lang(
@@ -340,7 +343,9 @@
             }
             ast::AssocItemKind::Const(ct) => (Target::AssocConst, Some(&ct.generics)),
             ast::AssocItemKind::Type(ty) => (Target::AssocTy, Some(&ty.generics)),
-            ast::AssocItemKind::MacCall(_) => unreachable!("macros should have been expanded"),
+            ast::AssocItemKind::MacCall(_) | ast::AssocItemKind::DelegationMac(_) => {
+                unreachable!("macros should have been expanded")
+            }
         };
 
         self.check_for_lang(
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index 4b5c4df..3b20112 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -13,7 +13,7 @@
 use rustc_span::{BytePos, Span};
 
 use crate::errors::{
-    BreakInsideAsyncBlock, BreakInsideClosure, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
+    BreakInsideClosure, BreakInsideCoroutine, BreakNonLoop, ContinueLabeledBlock, OutsideLoop,
     OutsideLoopSuggestion, UnlabeledCfInWhileCondition, UnlabeledInLabeledBlock,
 };
 
@@ -23,7 +23,7 @@
     Fn,
     Loop(hir::LoopSource),
     Closure(Span),
-    AsyncClosure(Span),
+    Coroutine { coroutine_span: Span, kind: hir::CoroutineDesugaring, source: hir::CoroutineSource },
     UnlabeledBlock(Span),
     LabeledBlock,
     Constant,
@@ -89,12 +89,10 @@
             hir::ExprKind::Closure(&hir::Closure {
                 ref fn_decl, body, fn_decl_span, kind, ..
             }) => {
-                // FIXME(coroutines): This doesn't handle coroutines correctly
                 let cx = match kind {
-                    hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(
-                        hir::CoroutineDesugaring::Async,
-                        hir::CoroutineSource::Block,
-                    )) => AsyncClosure(fn_decl_span),
+                    hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared(kind, source)) => {
+                        Coroutine { coroutine_span: fn_decl_span, kind, source }
+                    }
                     _ => Closure(fn_decl_span),
                 };
                 self.visit_fn_decl(fn_decl);
@@ -227,8 +225,24 @@
             Closure(closure_span) => {
                 self.sess.dcx().emit_err(BreakInsideClosure { span, closure_span, name });
             }
-            AsyncClosure(closure_span) => {
-                self.sess.dcx().emit_err(BreakInsideAsyncBlock { span, closure_span, name });
+            Coroutine { coroutine_span, kind, source } => {
+                let kind = match kind {
+                    hir::CoroutineDesugaring::Async => "async",
+                    hir::CoroutineDesugaring::Gen => "gen",
+                    hir::CoroutineDesugaring::AsyncGen => "async gen",
+                };
+                let source = match source {
+                    hir::CoroutineSource::Block => "block",
+                    hir::CoroutineSource::Closure => "closure",
+                    hir::CoroutineSource::Fn => "function",
+                };
+                self.sess.dcx().emit_err(BreakInsideCoroutine {
+                    span,
+                    coroutine_span,
+                    name,
+                    kind,
+                    source,
+                });
             }
             UnlabeledBlock(block_span) if is_break && block_span.eq_ctxt(break_span) => {
                 let suggestion = Some(OutsideLoopSuggestion { block_span, break_span });
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index d5e1a70..55b7c6d 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -1,14 +1,26 @@
-//! Finds local items that are externally reachable, which means that other crates need access to
-//! their compiled machine code or their MIR.
+//! Finds local items that are "reachable", which means that other crates need access to their
+//! compiled code or their *runtime* MIR. (Compile-time MIR is always encoded anyway, so we don't
+//! worry about that here.)
 //!
-//! An item is "externally reachable" if it is relevant for other crates. This obviously includes
-//! all public items. However, some of these items cannot be compiled to machine code (because they
-//! are generic), and for some the machine code is not sufficient (because we want to cross-crate
-//! inline them). These items "need cross-crate MIR". When a reachable function `f` needs
-//! cross-crate MIR, then all the functions it calls also become reachable, as they will be
-//! necessary to use the MIR of `f` from another crate. Furthermore, an item can become "externally
-//! reachable" by having a `const`/`const fn` return a pointer to that item, so we also need to
-//! recurse into reachable `const`/`const fn`.
+//! An item is "reachable" if codegen that happens in downstream crates can end up referencing this
+//! item. This obviously includes all public items. However, some of these items cannot be codegen'd
+//! (because they are generic), and for some the compiled code is not sufficient (because we want to
+//! cross-crate inline them). These items "need cross-crate MIR". When a reachable function `f`
+//! needs cross-crate MIR, then its MIR may be codegen'd in a downstream crate, and hence items it
+//! mentions need to be considered reachable.
+//!
+//! Furthermore, if a `const`/`const fn` is reachable, then it can return pointers to other items,
+//! making those reachable as well. For instance, consider a `const fn` returning a pointer to an
+//! otherwise entirely private function: if a downstream crate calls that `const fn` to compute the
+//! initial value of a `static`, then it needs to generate a direct reference to this function --
+//! i.e., the function is directly reachable from that downstream crate! Hence we have to recurse
+//! into `const` and `const fn`.
+//!
+//! Conversely, reachability *stops* when it hits a monomorphic non-`const` function that we do not
+//! want to cross-crate inline. That function will just be codegen'd in this crate, which means the
+//! monomorphization collector will consider it a root and then do another graph traversal to
+//! codegen everything called by this function -- but that's a very different graph from what we are
+//! considering here as at that point, everything is monomorphic.
 
 use hir::def_id::LocalDefIdSet;
 use rustc_data_structures::stack::ensure_sufficient_stack;
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index a78f7e6..f631ae7 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -20,6 +20,7 @@
 use rustc_hir::{AssocItemKind, ForeignItemKind, ItemId, ItemKind, PatKind};
 use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
 use rustc_middle::query::Providers;
+use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::GenericArgs;
 use rustc_middle::ty::{self, Const, GenericParamDefKind};
 use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
@@ -116,7 +117,7 @@
         if V::SHALLOW { V::Result::output() } else { args.visit_with(self) }
     }
 
-    fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> V::Result {
+    fn visit_projection_term(&mut self, projection: ty::AliasTerm<'tcx>) -> V::Result {
         let tcx = self.def_id_visitor.tcx();
         let (trait_ref, assoc_args) = projection.trait_ref_and_own_args(tcx);
         try_visit!(self.visit_trait(trait_ref));
@@ -134,9 +135,12 @@
             ty::ClauseKind::Trait(ty::TraitPredicate { trait_ref, polarity: _ }) => {
                 self.visit_trait(trait_ref)
             }
-            ty::ClauseKind::Projection(ty::ProjectionPredicate { projection_ty, term }) => {
+            ty::ClauseKind::Projection(ty::ProjectionPredicate {
+                projection_term: projection_ty,
+                term,
+            }) => {
                 try_visit!(term.visit_with(self));
-                self.visit_projection_ty(projection_ty)
+                self.visit_projection_term(projection_ty)
             }
             ty::ClauseKind::TypeOutlives(ty::OutlivesPredicate(ty, _region)) => ty.visit_with(self),
             ty::ClauseKind::RegionOutlives(..) => V::Result::output(),
@@ -225,7 +229,7 @@
                 return if V::SHALLOW {
                     V::Result::output()
                 } else if kind == ty::Projection {
-                    self.visit_projection_ty(data)
+                    self.visit_projection_term(data.into())
                 } else {
                     V::Result::from_branch(
                         data.args.iter().try_for_each(|arg| arg.visit_with(self).branch()),
@@ -787,7 +791,7 @@
 
 impl ReachEverythingInTheInterfaceVisitor<'_, '_> {
     fn generics(&mut self) -> &mut Self {
-        for param in &self.ev.tcx.generics_of(self.item_def_id).params {
+        for param in &self.ev.tcx.generics_of(self.item_def_id).own_params {
             match param.kind {
                 GenericParamDefKind::Lifetime => {}
                 GenericParamDefKind::Type { has_default, .. } => {
@@ -1259,7 +1263,7 @@
 impl SearchInterfaceForPrivateItemsVisitor<'_> {
     fn generics(&mut self) -> &mut Self {
         self.in_primary_interface = true;
-        for param in &self.tcx.generics_of(self.item_def_id).params {
+        for param in &self.tcx.generics_of(self.item_def_id).own_params {
             match param.kind {
                 GenericParamDefKind::Lifetime => {}
                 GenericParamDefKind::Type { has_default, .. } => {
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 914481d..85f5555 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -8,9 +8,6 @@
 #![allow(rustc::potential_query_instability, unused_parens)]
 #![allow(internal_features)]
 
-#[macro_use]
-extern crate rustc_middle;
-
 use crate::plumbing::{__rust_begin_short_backtrace, encode_all_query_results, try_mark_green};
 use crate::profiling_support::QueryKeyStringCache;
 use field_offset::offset_of;
@@ -222,4 +219,4 @@
     }
 }
 
-rustc_query_append! { define_queries! }
+rustc_middle::rustc_query_append! { define_queries! }
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index aa96577..86531bd 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -2,25 +2,23 @@
 //! generate the actual methods on tcx which find and execute the provider,
 //! manage the caches, and so forth.
 
-use crate::rustc_middle::dep_graph::DepContext;
-use crate::rustc_middle::ty::TyEncoder;
 use crate::QueryConfigRestored;
 use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
 use rustc_data_structures::sync::Lock;
 use rustc_data_structures::unord::UnordMap;
 use rustc_errors::DiagInner;
-
 use rustc_index::Idx;
+use rustc_middle::bug;
 use rustc_middle::dep_graph::dep_kinds;
 use rustc_middle::dep_graph::{
-    self, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex,
+    self, DepContext, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex,
 };
 use rustc_middle::query::on_disk_cache::AbsoluteBytePos;
 use rustc_middle::query::on_disk_cache::{CacheDecoder, CacheEncoder, EncodedDepNodeIndex};
 use rustc_middle::query::Key;
 use rustc_middle::ty::print::with_reduced_queries;
 use rustc_middle::ty::tls::{self, ImplicitCtxt};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, TyCtxt, TyEncoder};
 use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_query_system::query::{
@@ -783,6 +781,7 @@
         #[allow(nonstandard_style)]
         mod query_callbacks {
             use super::*;
+            use rustc_middle::bug;
             use rustc_query_system::dep_graph::FingerprintStyle;
 
             // We use this for most things when incr. comp. is turned off.
@@ -851,7 +850,7 @@
         }
 
         pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct<'tcx>] {
-            arena.alloc_from_iter(make_dep_kind_array!(query_callbacks))
+            arena.alloc_from_iter(rustc_middle::make_dep_kind_array!(query_callbacks))
         }
     }
 }
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index 8068ea1..689109b 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -32,6 +32,8 @@
 
 use std::cell::Cell;
 
+use tracing::debug;
+
 type Res = def::Res<NodeId>;
 
 impl<'a, Id: Into<DefId>> ToNameBinding<'a>
@@ -560,7 +562,7 @@
 
                 self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis);
             }
-            ast::UseTreeKind::Nested(ref items) => {
+            ast::UseTreeKind::Nested { ref items, .. } => {
                 // Ensure there is at most one `self` in the list
                 let self_spans = items
                     .iter()
@@ -825,7 +827,9 @@
             }
             ItemKind::Impl { .. } | ItemKind::ForeignMod(..) | ItemKind::GlobalAsm(..) => {}
 
-            ItemKind::MacroDef(..) | ItemKind::MacCall(_) => unreachable!(),
+            ItemKind::MacroDef(..) | ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => {
+                unreachable!()
+            }
         }
     }
 
@@ -1381,7 +1385,7 @@
                 | AssocItemKind::Delegation(..)
                 | AssocItemKind::Fn(..) => ValueNS,
                 AssocItemKind::Type(..) => TypeNS,
-                AssocItemKind::MacCall(_) => bug!(), // handled above
+                AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => bug!(), // handled above
             };
 
             let parent = self.parent_scope.module;
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index f6004fe..fc3669f 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -32,7 +32,7 @@
 use rustc_ast::visit::{self, Visitor};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
 use rustc_data_structures::unord::UnordSet;
-use rustc_errors::{pluralize, MultiSpan};
+use rustc_errors::MultiSpan;
 use rustc_hir::def::{DefKind, Res};
 use rustc_session::lint::builtin::{MACRO_USE_EXTERN_CRATE, UNUSED_EXTERN_CRATES};
 use rustc_session::lint::builtin::{UNUSED_IMPORTS, UNUSED_QUALIFICATIONS};
@@ -128,7 +128,7 @@
                     self.unused_import(self.base_id).add(id);
                 }
             }
-            ast::UseTreeKind::Nested(ref items) => self.check_imports_as_underscore(items),
+            ast::UseTreeKind::Nested { ref items, .. } => self.check_imports_as_underscore(items),
             _ => {}
         }
     }
@@ -151,11 +151,10 @@
             // We do this in any edition.
             if warn_if_unused {
                 if let Some(&span) = maybe_unused_extern_crates.get(&extern_crate.id) {
-                    self.r.lint_buffer.buffer_lint_with_diagnostic(
+                    self.r.lint_buffer.buffer_lint(
                         UNUSED_EXTERN_CRATES,
                         extern_crate.id,
                         span,
-                        "unused extern crate",
                         BuiltinLintDiag::UnusedExternCrate {
                             removal_span: extern_crate.span_with_attributes,
                         },
@@ -204,11 +203,10 @@
                 .span
                 .find_ancestor_inside(extern_crate.span)
                 .unwrap_or(extern_crate.ident.span);
-            self.r.lint_buffer.buffer_lint_with_diagnostic(
+            self.r.lint_buffer.buffer_lint(
                 UNUSED_EXTERN_CRATES,
                 extern_crate.id,
                 extern_crate.span,
-                "`extern crate` is not idiomatic in the new edition",
                 BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span },
             );
         }
@@ -254,7 +252,7 @@
             return;
         }
 
-        if let ast::UseTreeKind::Nested(ref items) = use_tree.kind {
+        if let ast::UseTreeKind::Nested { ref items, .. } = use_tree.kind {
             if items.is_empty() {
                 self.unused_import(self.base_id).add(id);
             }
@@ -268,9 +266,8 @@
 
 enum UnusedSpanResult {
     Used,
-    FlatUnused(Span, Span),
-    NestedFullUnused(Vec<Span>, Span),
-    NestedPartialUnused(Vec<Span>, Vec<Span>),
+    Unused { spans: Vec<Span>, remove: Span },
+    PartialUnused { spans: Vec<Span>, remove: Vec<Span> },
 }
 
 fn calc_unused_spans(
@@ -288,36 +285,33 @@
     match use_tree.kind {
         ast::UseTreeKind::Simple(..) | ast::UseTreeKind::Glob => {
             if unused_import.unused.contains(&use_tree_id) {
-                UnusedSpanResult::FlatUnused(use_tree.span, full_span)
+                UnusedSpanResult::Unused { spans: vec![use_tree.span], remove: full_span }
             } else {
                 UnusedSpanResult::Used
             }
         }
-        ast::UseTreeKind::Nested(ref nested) => {
+        ast::UseTreeKind::Nested { items: ref nested, span: tree_span } => {
             if nested.is_empty() {
-                return UnusedSpanResult::FlatUnused(use_tree.span, full_span);
+                return UnusedSpanResult::Unused { spans: vec![use_tree.span], remove: full_span };
             }
 
             let mut unused_spans = Vec::new();
             let mut to_remove = Vec::new();
-            let mut all_nested_unused = true;
+            let mut used_children = 0;
+            let mut contains_self = false;
             let mut previous_unused = false;
             for (pos, (use_tree, use_tree_id)) in nested.iter().enumerate() {
                 let remove = match calc_unused_spans(unused_import, use_tree, *use_tree_id) {
                     UnusedSpanResult::Used => {
-                        all_nested_unused = false;
+                        used_children += 1;
                         None
                     }
-                    UnusedSpanResult::FlatUnused(span, remove) => {
-                        unused_spans.push(span);
-                        Some(remove)
-                    }
-                    UnusedSpanResult::NestedFullUnused(mut spans, remove) => {
+                    UnusedSpanResult::Unused { mut spans, remove } => {
                         unused_spans.append(&mut spans);
                         Some(remove)
                     }
-                    UnusedSpanResult::NestedPartialUnused(mut spans, mut to_remove_extra) => {
-                        all_nested_unused = false;
+                    UnusedSpanResult::PartialUnused { mut spans, remove: mut to_remove_extra } => {
+                        used_children += 1;
                         unused_spans.append(&mut spans);
                         to_remove.append(&mut to_remove_extra);
                         None
@@ -326,7 +320,7 @@
                 if let Some(remove) = remove {
                     let remove_span = if nested.len() == 1 {
                         remove
-                    } else if pos == nested.len() - 1 || !all_nested_unused {
+                    } else if pos == nested.len() - 1 || used_children > 0 {
                         // Delete everything from the end of the last import, to delete the
                         // previous comma
                         nested[pos - 1].0.span.shrink_to_hi().to(use_tree.span)
@@ -344,14 +338,38 @@
                         to_remove.push(remove_span);
                     }
                 }
+                contains_self |= use_tree.prefix == kw::SelfLower
+                    && matches!(use_tree.kind, ast::UseTreeKind::Simple(None));
                 previous_unused = remove.is_some();
             }
             if unused_spans.is_empty() {
                 UnusedSpanResult::Used
-            } else if all_nested_unused {
-                UnusedSpanResult::NestedFullUnused(unused_spans, full_span)
+            } else if used_children == 0 {
+                UnusedSpanResult::Unused { spans: unused_spans, remove: full_span }
             } else {
-                UnusedSpanResult::NestedPartialUnused(unused_spans, to_remove)
+                // If there is only one remaining child that is used, the braces around the use
+                // tree are not needed anymore. In that case, we determine the span of the left
+                // brace and the right brace, and tell rustfix to remove them as well.
+                //
+                // This means that `use a::{B, C};` will be turned into `use a::B;` rather than
+                // `use a::{B};`, removing a rustfmt roundtrip.
+                //
+                // Note that we cannot remove the braces if the only item inside the use tree is
+                // `self`: `use foo::{self};` is valid Rust syntax, while `use foo::self;` errors
+                // out. We also cannot turn `use foo::{self}` into `use foo`, as the former doesn't
+                // import types with the same name as the module.
+                if used_children == 1 && !contains_self {
+                    // Left brace, from the start of the nested group to the first item.
+                    to_remove.push(
+                        tree_span.shrink_to_lo().to(nested.first().unwrap().0.span.shrink_to_lo()),
+                    );
+                    // Right brace, from the end of the last item to the end of the nested group.
+                    to_remove.push(
+                        nested.last().unwrap().0.span.shrink_to_hi().to(tree_span.shrink_to_hi()),
+                    );
+                }
+
+                UnusedSpanResult::PartialUnused { spans: unused_spans, remove: to_remove }
             }
         }
     }
@@ -374,10 +392,7 @@
                                 MACRO_USE_EXTERN_CRATE,
                                 import.root_id,
                                 import.span,
-                                "deprecated `#[macro_use]` attribute used to \
-                                import macros should be replaced at use sites \
-                                with a `use` item to import the macro \
-                                instead",
+                                BuiltinLintDiag::MacroUseDeprecated,
                             );
                         }
                     }
@@ -394,8 +409,12 @@
                     }
                 }
                 ImportKind::MacroUse { .. } => {
-                    let msg = "unused `#[macro_use]` import";
-                    self.lint_buffer.buffer_lint(UNUSED_IMPORTS, import.root_id, import.span, msg);
+                    self.lint_buffer.buffer_lint(
+                        UNUSED_IMPORTS,
+                        import.root_id,
+                        import.span,
+                        BuiltinLintDiag::UnusedMacroUse,
+                    );
                 }
                 _ => {}
             }
@@ -414,24 +433,12 @@
         visitor.report_unused_extern_crate_items(maybe_unused_extern_crates);
 
         for unused in visitor.unused_imports.values() {
-            let mut fixes = Vec::new();
-            let spans = match calc_unused_spans(unused, &unused.use_tree, unused.use_tree_id) {
-                UnusedSpanResult::Used => continue,
-                UnusedSpanResult::FlatUnused(span, remove) => {
-                    fixes.push((remove, String::new()));
-                    vec![span]
-                }
-                UnusedSpanResult::NestedFullUnused(spans, remove) => {
-                    fixes.push((remove, String::new()));
-                    spans
-                }
-                UnusedSpanResult::NestedPartialUnused(spans, remove) => {
-                    for fix in &remove {
-                        fixes.push((*fix, String::new()));
-                    }
-                    spans
-                }
-            };
+            let (spans, remove_spans) =
+                match calc_unused_spans(unused, &unused.use_tree, unused.use_tree_id) {
+                    UnusedSpanResult::Used => continue,
+                    UnusedSpanResult::Unused { spans, remove } => (spans, vec![remove]),
+                    UnusedSpanResult::PartialUnused { spans, remove } => (spans, remove),
+                };
 
             let ms = MultiSpan::from_spans(spans);
 
@@ -443,23 +450,8 @@
                 .collect::<Vec<String>>();
             span_snippets.sort();
 
-            let msg = format!(
-                "unused import{}{}",
-                pluralize!(ms.primary_spans().len()),
-                if !span_snippets.is_empty() {
-                    format!(": {}", span_snippets.join(", "))
-                } else {
-                    String::new()
-                }
-            );
-
-            let fix_msg = if fixes.len() == 1 && fixes[0].0 == unused.item_span {
-                "remove the whole `use` item"
-            } else if ms.primary_spans().len() > 1 {
-                "remove the unused imports"
-            } else {
-                "remove the unused import"
-            };
+            let remove_whole_use = remove_spans.len() == 1 && remove_spans[0] == unused.item_span;
+            let num_to_remove = ms.primary_spans().len();
 
             // If we are in the `--test` mode, suppress a help that adds the `#[cfg(test)]`
             // attribute; however, if not, suggest adding the attribute. There is no way to
@@ -485,12 +477,17 @@
                 }
             };
 
-            visitor.r.lint_buffer.buffer_lint_with_diagnostic(
+            visitor.r.lint_buffer.buffer_lint(
                 UNUSED_IMPORTS,
                 unused.use_tree_id,
                 ms,
-                msg,
-                BuiltinLintDiag::UnusedImports(fix_msg.into(), fixes, test_module_span),
+                BuiltinLintDiag::UnusedImports {
+                    remove_whole_use,
+                    num_to_remove,
+                    remove_spans,
+                    test_module_span,
+                    span_snippets,
+                },
             );
         }
 
@@ -536,11 +533,10 @@
                 continue;
             }
 
-            self.lint_buffer.buffer_lint_with_diagnostic(
+            self.lint_buffer.buffer_lint(
                 UNUSED_QUALIFICATIONS,
                 unn_qua.node_id,
                 unn_qua.path_span,
-                "unnecessary qualification",
                 BuiltinLintDiag::UnusedQualifications { removal_span: unn_qua.removal_span },
             );
         }
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index a27a6bc..bd06224 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -7,6 +7,7 @@
 use rustc_span::hygiene::LocalExpnId;
 use rustc_span::symbol::{kw, sym, Symbol};
 use rustc_span::Span;
+use tracing::debug;
 
 pub(crate) fn collect_definitions(
     resolver: &mut Resolver<'_, '_>,
@@ -139,6 +140,7 @@
             ItemKind::GlobalAsm(..) => DefKind::GlobalAsm,
             ItemKind::Use(..) => return visit::walk_item(self, i),
             ItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
+            ItemKind::DelegationMac(..) => unreachable!(),
         };
         let def_id = self.create_def(i.id, i.ident.name, def_kind, i.span);
 
@@ -278,6 +280,7 @@
             AssocItemKind::Const(..) => DefKind::AssocConst,
             AssocItemKind::Type(..) => DefKind::AssocTy,
             AssocItemKind::MacCall(..) => return self.visit_macro_invoc(i.id),
+            AssocItemKind::DelegationMac(..) => unreachable!(),
         };
 
         let def = self.create_def(i.id, i.ident.name, def_kind, i.span);
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 01e279b..856cfbc 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -28,6 +28,7 @@
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Span, SyntaxContext};
 use thin_vec::{thin_vec, ThinVec};
+use tracing::debug;
 
 use crate::errors::{
     self, AddedMacroUse, ChangeImportBinding, ChangeImportBindingSuggestion, ConsiderAddingADerive,
@@ -43,9 +44,6 @@
 use crate::{ParentScope, PathResult, ResolutionError, Resolver, Scope, ScopeSet};
 use crate::{Segment, UseError};
 
-#[cfg(test)]
-mod tests;
-
 type Res = def::Res<ast::NodeId>;
 
 /// A vector of spans and replacements, a message and applicability.
@@ -130,13 +128,10 @@
         self.report_with_use_injections(krate);
 
         for &(span_use, span_def) in &self.macro_expanded_macro_export_errors {
-            let msg = "macro-expanded `macro_export` macros from the current crate \
-                       cannot be referred to by absolute paths";
-            self.lint_buffer.buffer_lint_with_diagnostic(
+            self.lint_buffer.buffer_lint(
                 MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
                 CRATE_NODE_ID,
                 span_use,
-                msg,
                 BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def),
             );
         }
@@ -147,11 +142,10 @@
                 let NameBindingKind::Import { import, .. } = ambiguity_error.b1.0.kind else {
                     unreachable!()
                 };
-                self.lint_buffer.buffer_lint_with_diagnostic(
+                self.lint_buffer.buffer_lint(
                     AMBIGUOUS_GLOB_IMPORTS,
                     import.root_id,
                     ambiguity_error.ident.span,
-                    diag.msg.to_string(),
                     BuiltinLintDiag::AmbiguousGlobImports { diag },
                 );
             } else {
@@ -528,12 +522,10 @@
         }
 
         let diag = BuiltinLintDiag::AbsPathWithModule(root_span);
-        self.lint_buffer.buffer_lint_with_diagnostic(
+        self.lint_buffer.buffer_lint(
             ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
             node_id,
             root_span,
-            "absolute paths must start with `self`, `super`, \
-             `crate`, or an external crate name in the 2018 edition",
             diag,
         );
     }
@@ -3026,14 +3018,3 @@
     // import or other generated ones
     !s.from_expansion()
 }
-
-/// Convert the given number into the corresponding ordinal
-pub(crate) fn ordinalize(v: usize) -> String {
-    let suffix = match ((11..=13).contains(&(v % 100)), v % 10) {
-        (false, 1) => "st",
-        (false, 2) => "nd",
-        (false, 3) => "rd",
-        _ => "th",
-    };
-    format!("{v}{suffix}")
-}
diff --git a/compiler/rustc_resolve/src/diagnostics/tests.rs b/compiler/rustc_resolve/src/diagnostics/tests.rs
deleted file mode 100644
index 2aa6cc6..0000000
--- a/compiler/rustc_resolve/src/diagnostics/tests.rs
+++ /dev/null
@@ -1,40 +0,0 @@
-use super::ordinalize;
-
-#[test]
-fn test_ordinalize() {
-    assert_eq!(ordinalize(1), "1st");
-    assert_eq!(ordinalize(2), "2nd");
-    assert_eq!(ordinalize(3), "3rd");
-    assert_eq!(ordinalize(4), "4th");
-    assert_eq!(ordinalize(5), "5th");
-    // ...
-    assert_eq!(ordinalize(10), "10th");
-    assert_eq!(ordinalize(11), "11th");
-    assert_eq!(ordinalize(12), "12th");
-    assert_eq!(ordinalize(13), "13th");
-    assert_eq!(ordinalize(14), "14th");
-    // ...
-    assert_eq!(ordinalize(20), "20th");
-    assert_eq!(ordinalize(21), "21st");
-    assert_eq!(ordinalize(22), "22nd");
-    assert_eq!(ordinalize(23), "23rd");
-    assert_eq!(ordinalize(24), "24th");
-    // ...
-    assert_eq!(ordinalize(30), "30th");
-    assert_eq!(ordinalize(31), "31st");
-    assert_eq!(ordinalize(32), "32nd");
-    assert_eq!(ordinalize(33), "33rd");
-    assert_eq!(ordinalize(34), "34th");
-    // ...
-    assert_eq!(ordinalize(7010), "7010th");
-    assert_eq!(ordinalize(7011), "7011th");
-    assert_eq!(ordinalize(7012), "7012th");
-    assert_eq!(ordinalize(7013), "7013th");
-    assert_eq!(ordinalize(7014), "7014th");
-    // ...
-    assert_eq!(ordinalize(7020), "7020th");
-    assert_eq!(ordinalize(7021), "7021st");
-    assert_eq!(ordinalize(7022), "7022nd");
-    assert_eq!(ordinalize(7023), "7023rd");
-    assert_eq!(ordinalize(7024), "7024th");
-}
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index 3443bbe..aab4a33 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -11,6 +11,7 @@
 use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility};
 use rustc_middle::ty::Visibility;
 use std::mem;
+use tracing::info;
 
 #[derive(Clone, Copy)]
 enum ParentId<'a> {
@@ -236,7 +237,7 @@
             ast::ItemKind::Impl(..) => return,
 
             // Should be unreachable at this stage
-            ast::ItemKind::MacCall(..) => panic!(
+            ast::ItemKind::MacCall(..) | ast::ItemKind::DelegationMac(..) => panic!(
                 "ast::ItemKind::MacCall encountered, this should not anymore appear at this stage"
             ),
 
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 43a43e0..57db765 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -11,6 +11,7 @@
 use rustc_span::sym;
 use rustc_span::symbol::{kw, Ident};
 use rustc_span::Span;
+use tracing::{debug, instrument};
 
 use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
 use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind};
@@ -523,18 +524,15 @@
                         match binding {
                             Ok(binding) => {
                                 if let Some(lint_id) = derive_fallback_lint_id {
-                                    this.lint_buffer.buffer_lint_with_diagnostic(
+                                    this.lint_buffer.buffer_lint(
                                         PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
                                         lint_id,
                                         orig_ident.span,
-                                        format!(
-                                            "cannot find {} `{}` in this scope",
-                                            ns.descr(),
-                                            ident
-                                        ),
-                                        BuiltinLintDiag::ProcMacroDeriveResolutionFallback(
-                                            orig_ident.span,
-                                        ),
+                                        BuiltinLintDiag::ProcMacroDeriveResolutionFallback {
+                                            span: orig_ident.span,
+                                            ns,
+                                            ident,
+                                        },
                                     );
                                 }
                                 let misc_flags = if module == this.graph_root {
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 3d9380a..51b87c5 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -34,6 +34,7 @@
 use rustc_span::symbol::{kw, Ident, Symbol};
 use rustc_span::Span;
 use smallvec::SmallVec;
+use tracing::debug;
 
 use std::cell::Cell;
 use std::mem;
@@ -618,11 +619,10 @@
                         && binding.res() != Res::Err
                         && exported_ambiguities.contains(&binding)
                     {
-                        self.lint_buffer.buffer_lint_with_diagnostic(
+                        self.lint_buffer.buffer_lint(
                             AMBIGUOUS_GLOB_REEXPORTS,
                             import.root_id,
                             import.root_span,
-                            "ambiguous glob re-exports",
                             BuiltinLintDiag::AmbiguousGlobReexports {
                                 name: key.ident.to_string(),
                                 namespace: key.ns.descr().to_string(),
@@ -654,11 +654,10 @@
                             && glob_binding.vis.is_public()
                             && !binding.vis.is_public()
                         {
-                            self.lint_buffer.buffer_lint_with_diagnostic(
+                            self.lint_buffer.buffer_lint(
                                 HIDDEN_GLOB_REEXPORTS,
                                 binding_id,
                                 binding.span,
-                                "private item shadows public glob re-export",
                                 BuiltinLintDiag::HiddenGlobReexports {
                                     name: key.ident.name.to_string(),
                                     namespace: key.ns.descr().to_owned(),
@@ -1014,17 +1013,13 @@
                         && !max_vis.is_at_least(import_vis, self.tcx)
                     {
                         let def_id = self.local_def_id(id);
-                        let msg = format!(
-                            "glob import doesn't reexport anything with visibility `{}` because no imported item is public enough",
-                            import_vis.to_string(def_id, self.tcx)
-                        );
-                        self.lint_buffer.buffer_lint_with_diagnostic(
+                        self.lint_buffer.buffer_lint(
                             UNUSED_IMPORTS,
                             id,
                             import.span,
-                            msg,
                             BuiltinLintDiag::RedundantImportVisibility {
                                 max_vis: max_vis.to_string(def_id, self.tcx),
+                                import_vis: import_vis.to_string(def_id, self.tcx),
                                 span: import.span,
                             },
                         );
@@ -1251,16 +1246,11 @@
         if !any_successful_reexport {
             let (ns, binding) = reexport_error.unwrap();
             if pub_use_of_private_extern_crate_hack(import, binding) {
-                let msg = format!(
-                    "extern crate `{ident}` is private, and cannot be \
-                                   re-exported (error E0365), consider declaring with \
-                                   `pub`"
-                );
                 self.lint_buffer.buffer_lint(
                     PUB_USE_OF_PRIVATE_EXTERN_CRATE,
                     import_id,
                     import.span,
-                    msg,
+                    BuiltinLintDiag::PrivateExternCrateReexport(ident),
                 );
             } else {
                 if ns == TypeNS {
@@ -1396,7 +1386,6 @@
                 UNUSED_IMPORTS,
                 id,
                 import.span,
-                format!("the item `{source}` is imported redundantly"),
                 BuiltinLintDiag::RedundantImport(redundant_spans, source),
             );
             */
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 6c870dd..d1d0e33 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -24,12 +24,13 @@
 use rustc_middle::ty::DelegationFnSig;
 use rustc_middle::{bug, span_bug};
 use rustc_session::config::{CrateType, ResolveDocLinks};
-use rustc_session::lint;
+use rustc_session::lint::{self, BuiltinLintDiag};
 use rustc_session::parse::feature_err;
 use rustc_span::source_map::{respan, Spanned};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, Span, SyntaxContext};
 use smallvec::{smallvec, SmallVec};
+use tracing::{debug, instrument, trace};
 
 use std::assert_matches::debug_assert_matches;
 use std::borrow::Cow;
@@ -1674,16 +1675,10 @@
                     return;
                 }
                 LifetimeRibKind::AnonymousWarn(node_id) => {
-                    let msg = if elided {
-                        "`&` without an explicit lifetime name cannot be used here"
-                    } else {
-                        "`'_` cannot be used here"
-                    };
-                    self.r.lint_buffer.buffer_lint_with_diagnostic(
+                    self.r.lint_buffer.buffer_lint(
                         lint::builtin::ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT,
                         node_id,
                         lifetime.ident.span,
-                        msg,
                         lint::BuiltinLintDiag::AssociatedConstElidedLifetime {
                             elided,
                             span: lifetime.ident.span,
@@ -1965,11 +1960,10 @@
             }
 
             if should_lint {
-                self.r.lint_buffer.buffer_lint_with_diagnostic(
+                self.r.lint_buffer.buffer_lint(
                     lint::builtin::ELIDED_LIFETIMES_IN_PATHS,
                     segment_id,
                     elided_lifetime_span,
-                    "hidden lifetime parameters in types are deprecated",
                     lint::BuiltinLintDiag::ElidedLifetimesInPaths(
                         expected_lifetimes,
                         path_span,
@@ -2347,8 +2341,8 @@
                     None => {}
                 }
             }
-        } else if let UseTreeKind::Nested(use_trees) = &use_tree.kind {
-            for (use_tree, _) in use_trees {
+        } else if let UseTreeKind::Nested { items, .. } = &use_tree.kind {
+            for (use_tree, _) in items {
                 self.future_proof_import(use_tree);
             }
         }
@@ -2525,7 +2519,7 @@
             ItemKind::Use(ref use_tree) => {
                 let maybe_exported = match use_tree.kind {
                     UseTreeKind::Simple(_) | UseTreeKind::Glob => MaybeExported::Ok(item.id),
-                    UseTreeKind::Nested(_) => MaybeExported::NestedUse(&item.vis),
+                    UseTreeKind::Nested { .. } => MaybeExported::NestedUse(&item.vis),
                 };
                 self.resolve_doc_links(&item.attrs, maybe_exported);
 
@@ -2561,7 +2555,9 @@
 
             ItemKind::ExternCrate(..) => {}
 
-            ItemKind::MacCall(_) => panic!("unexpanded macro in resolve!"),
+            ItemKind::MacCall(_) | ItemKind::DelegationMac(..) => {
+                panic!("unexpanded macro in resolve!")
+            }
         }
     }
 
@@ -2849,7 +2845,7 @@
                     .with_lifetime_rib(LifetimeRibKind::AnonymousReportError, |this| {
                         walk_assoc_item(this, generics, LifetimeBinderKind::Item, item)
                     }),
-                AssocItemKind::MacCall(_) => {
+                AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => {
                     panic!("unexpanded macro in resolve!")
                 }
             };
@@ -3116,7 +3112,7 @@
                     },
                 );
             }
-            AssocItemKind::MacCall(_) => {
+            AssocItemKind::MacCall(_) | AssocItemKind::DelegationMac(..) => {
                 panic!("unexpanded macro in resolve!")
             }
         }
@@ -3218,7 +3214,9 @@
             AssocItemKind::Fn(..) => (E0324, "method"),
             AssocItemKind::Type(..) => (E0325, "type"),
             AssocItemKind::Delegation(..) => (E0324, "method"),
-            AssocItemKind::MacCall(..) => span_bug!(span, "unexpanded macro"),
+            AssocItemKind::MacCall(..) | AssocItemKind::DelegationMac(..) => {
+                span_bug!(span, "unexpanded macro")
+            }
         };
         let trait_path = path_names_to_string(path);
         self.report_error(
@@ -4790,7 +4788,8 @@
             | ItemKind::ExternCrate(..)
             | ItemKind::MacroDef(..)
             | ItemKind::GlobalAsm(..)
-            | ItemKind::MacCall(..) => {}
+            | ItemKind::MacCall(..)
+            | ItemKind::DelegationMac(..) => {}
             ItemKind::Delegation(..) => {
                 // Delegated functions have lifetimes, their count is not necessarily zero.
                 // But skipping the delegation items here doesn't mean that the count will be considered zero,
@@ -4816,7 +4815,12 @@
         late_resolution_visitor.resolve_doc_links(&krate.attrs, MaybeExported::Ok(CRATE_NODE_ID));
         visit::walk_crate(&mut late_resolution_visitor, krate);
         for (id, span) in late_resolution_visitor.diag_metadata.unused_labels.iter() {
-            self.lint_buffer.buffer_lint(lint::builtin::UNUSED_LABELS, *id, *span, "unused label");
+            self.lint_buffer.buffer_lint(
+                lint::builtin::UNUSED_LABELS,
+                *id,
+                *span,
+                BuiltinLintDiag::UnusedLabel,
+            );
         }
     }
 }
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 6445103..9daa22f 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -17,6 +17,7 @@
 };
 use rustc_ast_pretty::pprust::where_bound_predicate_to_string;
 use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{
     codes::*, pluralize, struct_span_code_err, Applicability, Diag, ErrorGuaranteed, MultiSpan,
     SuggestionStyle,
@@ -31,7 +32,7 @@
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
 
 use rustc_middle::ty;
 
@@ -40,6 +41,7 @@
 use std::ops::Deref;
 
 use thin_vec::ThinVec;
+use tracing::debug;
 
 use super::NoConstantGenericsReason;
 
@@ -2045,7 +2047,9 @@
                             AssocSuggestion::MethodWithSelf { called }
                         }
                         ast::AssocItemKind::Delegation(..) => AssocSuggestion::AssocFn { called },
-                        ast::AssocItemKind::MacCall(_) => continue,
+                        ast::AssocItemKind::MacCall(_) | ast::AssocItemKind::DelegationMac(..) => {
+                            continue;
+                        }
                     });
                 }
             }
@@ -2648,15 +2652,15 @@
                     let deletion_span =
                         if param.bounds.is_empty() { deletion_span() } else { None };
 
-                    self.r.lint_buffer.buffer_lint_with_diagnostic(
+                    self.r.lint_buffer.buffer_lint(
                         lint::builtin::SINGLE_USE_LIFETIMES,
                         param.id,
                         param.ident.span,
-                        format!("lifetime parameter `{}` only used once", param.ident),
                         lint::BuiltinLintDiag::SingleUseLifetime {
                             param_span: param.ident.span,
                             use_span: Some((use_span, elidable)),
                             deletion_span,
+                            ident: param.ident,
                         },
                     );
                 }
@@ -2666,15 +2670,15 @@
 
                     // if the lifetime originates from expanded code, we won't be able to remove it #104432
                     if deletion_span.is_some_and(|sp| !sp.in_derive_expansion()) {
-                        self.r.lint_buffer.buffer_lint_with_diagnostic(
+                        self.r.lint_buffer.buffer_lint(
                             lint::builtin::UNUSED_LIFETIMES,
                             param.id,
                             param.ident.span,
-                            format!("lifetime parameter `{}` never used", param.ident),
                             lint::BuiltinLintDiag::SingleUseLifetime {
                                 param_span: param.ident.span,
                                 use_span: None,
                                 deletion_span,
+                                ident: param.ident,
                             },
                         );
                     }
@@ -2711,8 +2715,17 @@
         self.suggest_introducing_lifetime(
             &mut err,
             Some(lifetime_ref.ident.name.as_str()),
-            |err, _, span, message, suggestion| {
-                err.span_suggestion(span, message, suggestion, Applicability::MaybeIncorrect);
+            |err, _, span, message, suggestion, span_suggs| {
+                err.multipart_suggestion_with_style(
+                    message,
+                    std::iter::once((span, suggestion)).chain(span_suggs.clone()).collect(),
+                    Applicability::MaybeIncorrect,
+                    if span_suggs.is_empty() {
+                        SuggestionStyle::ShowCode
+                    } else {
+                        SuggestionStyle::ShowAlways
+                    },
+                );
                 true
             },
         );
@@ -2723,13 +2736,20 @@
         &self,
         err: &mut Diag<'_>,
         name: Option<&str>,
-        suggest: impl Fn(&mut Diag<'_>, bool, Span, Cow<'static, str>, String) -> bool,
+        suggest: impl Fn(
+            &mut Diag<'_>,
+            bool,
+            Span,
+            Cow<'static, str>,
+            String,
+            Vec<(Span, String)>,
+        ) -> bool,
     ) {
         let mut suggest_note = true;
         for rib in self.lifetime_ribs.iter().rev() {
             let mut should_continue = true;
             match rib.kind {
-                LifetimeRibKind::Generics { binder: _, span, kind } => {
+                LifetimeRibKind::Generics { binder, span, kind } => {
                     // Avoid suggesting placing lifetime parameters on constant items unless the relevant
                     // feature is enabled. Suggest the parent item as a possible location if applicable.
                     if let LifetimeBinderKind::ConstItem = kind
@@ -2758,11 +2778,53 @@
                             | LifetimeBinderKind::PolyTrait
                             | LifetimeBinderKind::WhereBound
                     );
+
+                    let mut rm_inner_binders: FxIndexSet<Span> = Default::default();
                     let (span, sugg) = if span.is_empty() {
+                        let mut binder_idents: FxIndexSet<Ident> = Default::default();
+                        binder_idents.insert(Ident::from_str(name.unwrap_or("'a")));
+
+                        // We need to special case binders in the following situation:
+                        // Change `T: for<'a> Trait<T> + 'b` to `for<'a, 'b> T: Trait<T> + 'b`
+                        // T: for<'a> Trait<T> + 'b
+                        //    ^^^^^^^  remove existing inner binder `for<'a>`
+                        // for<'a, 'b> T: Trait<T> + 'b
+                        // ^^^^^^^^^^^  suggest outer binder `for<'a, 'b>`
+                        if let LifetimeBinderKind::WhereBound = kind
+                            && let Some(ast::WherePredicate::BoundPredicate(
+                                ast::WhereBoundPredicate { bounded_ty, bounds, .. },
+                            )) = self.diag_metadata.current_where_predicate
+                            && bounded_ty.id == binder
+                        {
+                            for bound in bounds {
+                                if let ast::GenericBound::Trait(poly_trait_ref, _) = bound
+                                    && let span = poly_trait_ref
+                                        .span
+                                        .with_hi(poly_trait_ref.trait_ref.path.span.lo())
+                                    && !span.is_empty()
+                                {
+                                    rm_inner_binders.insert(span);
+                                    poly_trait_ref.bound_generic_params.iter().for_each(|v| {
+                                        binder_idents.insert(v.ident);
+                                    });
+                                }
+                            }
+                        }
+
+                        let binders_sugg = binder_idents.into_iter().enumerate().fold(
+                            "".to_string(),
+                            |mut binders, (i, x)| {
+                                if i != 0 {
+                                    binders += ", ";
+                                }
+                                binders += x.as_str();
+                                binders
+                            },
+                        );
                         let sugg = format!(
                             "{}<{}>{}",
                             if higher_ranked { "for" } else { "" },
-                            name.unwrap_or("'a"),
+                            binders_sugg,
                             if higher_ranked { " " } else { "" },
                         );
                         (span, sugg)
@@ -2777,13 +2839,28 @@
                         let sugg = format!("{}, ", name.unwrap_or("'a"));
                         (span, sugg)
                     };
+
                     if higher_ranked {
                         let message = Cow::from(format!(
                             "consider making the {} lifetime-generic with a new `{}` lifetime",
                             kind.descr(),
                             name.unwrap_or("'a"),
                         ));
-                        should_continue = suggest(err, true, span, message, sugg);
+                        should_continue = suggest(
+                            err,
+                            true,
+                            span,
+                            message,
+                            sugg,
+                            if !rm_inner_binders.is_empty() {
+                                rm_inner_binders
+                                    .into_iter()
+                                    .map(|v| (v, "".to_string()))
+                                    .collect::<Vec<_>>()
+                            } else {
+                                vec![]
+                            },
+                        );
                         err.note_once(
                             "for more information on higher-ranked polymorphism, visit \
                              https://doc.rust-lang.org/nomicon/hrtb.html",
@@ -2791,10 +2868,10 @@
                     } else if let Some(name) = name {
                         let message =
                             Cow::from(format!("consider introducing lifetime `{name}` here"));
-                        should_continue = suggest(err, false, span, message, sugg);
+                        should_continue = suggest(err, false, span, message, sugg, vec![]);
                     } else {
                         let message = Cow::from("consider introducing a named lifetime parameter");
-                        should_continue = suggest(err, false, span, message, sugg);
+                        should_continue = suggest(err, false, span, message, sugg, vec![]);
                     }
                 }
                 LifetimeRibKind::Item | LifetimeRibKind::ConstParamTy => break,
@@ -3030,11 +3107,11 @@
                 self.suggest_introducing_lifetime(
                     err,
                     None,
-                    |err, higher_ranked, span, message, intro_sugg| {
+                    |err, higher_ranked, span, message, intro_sugg, _| {
                         err.multipart_suggestion_verbose(
                             message,
                             std::iter::once((span, intro_sugg))
-                                .chain(spans_suggs.iter().cloned())
+                                .chain(spans_suggs.clone())
                                 .collect(),
                             Applicability::MaybeIncorrect,
                         );
@@ -3158,11 +3235,11 @@
                             self.suggest_introducing_lifetime(
                                 err,
                                 None,
-                                |err, higher_ranked, span, message, intro_sugg| {
+                                |err, higher_ranked, span, message, intro_sugg, _| {
                                     err.multipart_suggestion_verbose(
                                         message,
                                         std::iter::once((span, intro_sugg))
-                                            .chain(spans_suggs.iter().cloned())
+                                            .chain(spans_suggs.clone())
                                             .collect(),
                                         Applicability::MaybeIncorrect,
                                     );
@@ -3306,7 +3383,6 @@
     poly_trait_ref: &ast::PolyTraitRef,
     ty: &Ty,
 ) -> Option<ast::WhereBoundPredicate> {
-    use rustc_span::DUMMY_SP;
     let modified_segments = {
         let mut segments = path.segments.clone();
         let [preceding @ .., second_last, last] = segments.as_mut_slice() else {
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index af0b479..f4c5ad8 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -6,9 +6,13 @@
 //!
 //! Type-relative name resolution (methods, fields, associated items) happens in `rustc_hir_analysis`.
 
+// tidy-alphabetical-start
+#![allow(internal_features)]
+#![allow(rustc::diagnostic_outside_of_impl)]
+#![allow(rustc::potential_query_instability)]
+#![allow(rustc::untranslatable_diagnostic)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
-#![feature(rustdoc_internals)]
 #![feature(assert_matches)]
 #![feature(box_patterns)]
 #![feature(extract_if)]
@@ -16,18 +20,9 @@
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
 #![feature(rustc_attrs)]
-#![allow(rustdoc::private_intra_doc_links)]
-#![allow(rustc::diagnostic_outside_of_impl)]
-#![allow(rustc::potential_query_instability)]
-#![allow(rustc::untranslatable_diagnostic)]
-#![allow(internal_features)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
 
-#[macro_use]
-extern crate tracing;
-
-use errors::{
-    ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst, ParamKindInTyOfConstParam,
-};
 use rustc_arena::{DroplessArena, TypedArena};
 use rustc_ast::expand::StrippedCfgItem;
 use rustc_ast::node_id::NodeMap;
@@ -56,23 +51,25 @@
 use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs, TyCtxt, TyCtxtFeed};
 use rustc_query_system::ich::StableHashingContext;
 use rustc_session::lint::builtin::PRIVATE_MACRO_USE;
-use rustc_session::lint::LintBuffer;
+use rustc_session::lint::{BuiltinLintDiag, LintBuffer};
 use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency};
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
-
 use smallvec::{smallvec, SmallVec};
 use std::cell::{Cell, RefCell};
 use std::collections::BTreeSet;
 use std::fmt;
+use tracing::debug;
 
 use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
+use effective_visibilities::EffectiveVisibilitiesVisitor;
+use errors::{
+    ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst, ParamKindInTyOfConstParam,
+};
 use imports::{Import, ImportData, ImportKind, NameResolution};
 use late::{HasGenericParams, PathSource, PatternSource, UnnecessaryQualification};
 use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
 
-use crate::effective_visibilities::EffectiveVisibilitiesVisitor;
-
 type Res = def::Res<NodeId>;
 
 mod build_reduced_graph;
@@ -964,7 +961,6 @@
     has_derive_copy: bool,
 }
 
-#[derive(Clone)]
 struct MacroData {
     ext: Lrc<SyntaxExtension>,
     rule_spans: Vec<(usize, Span)>,
@@ -1864,8 +1860,12 @@
         }
         if let NameBindingKind::Import { import, binding } = used_binding.kind {
             if let ImportKind::MacroUse { warn_private: true } = import.kind {
-                let msg = format!("macro `{ident}` is private");
-                self.lint_buffer().buffer_lint(PRIVATE_MACRO_USE, import.root_id, ident.span, msg);
+                self.lint_buffer().buffer_lint(
+                    PRIVATE_MACRO_USE,
+                    import.root_id,
+                    ident.span,
+                    BuiltinLintDiag::MacroIsPrivate(ident),
+                );
             }
             // Avoid marking `extern crate` items that refer to a name from extern prelude,
             // but not introduce it, as used if they are accessed from lexical scope.
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 35bf3f7..268e7f0 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -29,6 +29,7 @@
 use rustc_session::lint::builtin::{UNUSED_MACROS, UNUSED_MACRO_RULES};
 use rustc_session::lint::BuiltinLintDiag;
 use rustc_session::parse::feature_err;
+use rustc_span::edit_distance::edit_distance;
 use rustc_span::edition::Edition;
 use rustc_span::hygiene::{self, ExpnData, ExpnKind, LocalExpnId};
 use rustc_span::hygiene::{AstPass, MacroKind};
@@ -314,7 +315,7 @@
                 UNUSED_MACROS,
                 node_id,
                 ident.span,
-                format!("unused macro definition: `{}`", ident.name),
+                BuiltinLintDiag::UnusedMacroDefinition(ident.name),
             );
         }
         for (&(def_id, arm_i), &(ident, rule_span)) in self.unused_macro_rules.iter() {
@@ -327,11 +328,7 @@
                 UNUSED_MACRO_RULES,
                 node_id,
                 rule_span,
-                format!(
-                    "{} rule of macro `{}` is never used",
-                    crate::diagnostics::ordinalize(arm_i + 1),
-                    ident.name
-                ),
+                BuiltinLintDiag::MacroRuleNeverUsed(arm_i, ident.name),
             );
         }
     }
@@ -555,28 +552,46 @@
 
         // We are trying to avoid reporting this error if other related errors were reported.
         if res != Res::Err && inner_attr && !self.tcx.features().custom_inner_attributes {
-            let msg = match res {
-                Res::Def(..) => "inner macro attributes are unstable",
-                Res::NonMacroAttr(..) => "custom inner attributes are unstable",
+            let is_macro = match res {
+                Res::Def(..) => true,
+                Res::NonMacroAttr(..) => false,
                 _ => unreachable!(),
             };
             if soft_custom_inner_attributes_gate {
-                self.tcx.sess.psess.buffer_lint(SOFT_UNSTABLE, path.span, node_id, msg);
+                self.tcx.sess.psess.buffer_lint(
+                    SOFT_UNSTABLE,
+                    path.span,
+                    node_id,
+                    BuiltinLintDiag::InnerAttributeUnstable { is_macro },
+                );
             } else {
+                // FIXME: deduplicate with rustc_lint (`BuiltinLintDiag::InnerAttributeUnstable`)
+                let msg = if is_macro {
+                    "inner macro attributes are unstable"
+                } else {
+                    "custom inner attributes are unstable"
+                };
                 feature_err(&self.tcx.sess, sym::custom_inner_attributes, path.span, msg).emit();
             }
         }
 
         if res == Res::NonMacroAttr(NonMacroAttrKind::Tool)
-            && path.segments.len() >= 2
-            && path.segments[0].ident.name == sym::diagnostic
-            && path.segments[1].ident.name != sym::on_unimplemented
+            && let [namespace, attribute, ..] = &*path.segments
+            && namespace.ident.name == sym::diagnostic
+            && !(attribute.ident.name == sym::on_unimplemented
+                || (attribute.ident.name == sym::do_not_recommend
+                    && self.tcx.features().do_not_recommend))
         {
+            let distance =
+                edit_distance(attribute.ident.name.as_str(), sym::on_unimplemented.as_str(), 5);
+
+            let typo_name = distance.map(|_| sym::on_unimplemented);
+
             self.tcx.sess.psess.buffer_lint(
                 UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                path.segments[1].span(),
+                attribute.span(),
                 node_id,
-                "unknown diagnostic attribute",
+                BuiltinLintDiag::UnknownDiagnosticAttribute { span: attribute.span(), typo_name },
             );
         }
 
@@ -776,11 +791,10 @@
                             .invocation_parents
                             .get(&parent_scope.expansion)
                             .map_or(ast::CRATE_NODE_ID, |id| self.def_id_to_node_id[id.0]);
-                        self.lint_buffer.buffer_lint_with_diagnostic(
+                        self.lint_buffer.buffer_lint(
                             LEGACY_DERIVE_HELPERS,
                             node_id,
                             ident.span,
-                            "derive helper attribute is used before it is introduced",
                             BuiltinLintDiag::LegacyDeriveHelpers(binding.span),
                         );
                     }
@@ -830,8 +844,17 @@
                 let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature));
                 if !is_allowed(feature) && !allowed_by_implication {
                     let lint_buffer = &mut self.lint_buffer;
-                    let soft_handler =
-                        |lint, span, msg: String| lint_buffer.buffer_lint(lint, node_id, span, msg);
+                    let soft_handler = |lint, span, msg: String| {
+                        lint_buffer.buffer_lint(
+                            lint,
+                            node_id,
+                            span,
+                            BuiltinLintDiag::UnstableFeature(
+                                // FIXME make this translatable
+                                msg.into(),
+                            ),
+                        )
+                    };
                     stability::report_unstable(
                         self.tcx.sess,
                         feature,
@@ -847,14 +870,12 @@
         }
         if let Some(depr) = &ext.deprecation {
             let path = pprust::path_to_string(path);
-            let (message, lint) = stability::deprecation_message_and_lint(depr, "macro", &path);
-            stability::early_report_deprecation(
+            stability::early_report_macro_deprecation(
                 &mut self.lint_buffer,
-                message,
-                depr.suggestion,
-                lint,
+                depr,
                 span,
                 node_id,
+                path,
             );
         }
     }
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index aace0f3..66b4981 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -8,6 +8,7 @@
 use rustc_span::{InnerSpan, Span, DUMMY_SP};
 use std::mem;
 use std::ops::Range;
+use tracing::{debug, trace};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug)]
 pub enum DocFragmentKind {
diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
index 7141c6c..62eb07e 100644
--- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
+++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs
@@ -8,7 +8,8 @@
 use rustc_middle::bug;
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{
-    self, Instance, IntTy, List, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, UintTy,
+    self, ExistentialPredicateStableCmpExt as _, Instance, IntTy, List, Ty, TyCtxt, TypeFoldable,
+    TypeVisitableExt, UintTy,
 };
 use rustc_span::sym;
 use rustc_trait_selection::traits;
@@ -268,7 +269,7 @@
 /// if a function is member of the group derived from this type id. Therefore, in the first call to
 /// typeid_for_fnabi (when type ids are attached to functions and methods), it can only include at
 /// most as much information that would be available in the second call (i.e., during code
-/// generation at call sites); otherwise, the type ids would not not match.
+/// generation at call sites); otherwise, the type ids would not match.
 ///
 /// For this, it:
 ///
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index f2bdabb..7dd9fdf 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -798,6 +798,7 @@
     Never,
 }
 
+#[derive(Clone)]
 pub enum Input {
     /// Load source code from a file.
     File(PathBuf),
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index f6053f4..df07f81 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -305,32 +305,12 @@
         lint: &'static Lint,
         span: impl Into<MultiSpan>,
         node_id: NodeId,
-        msg: impl Into<DiagMessage>,
-    ) {
-        self.buffered_lints.with_lock(|buffered_lints| {
-            buffered_lints.push(BufferedEarlyLint {
-                span: span.into(),
-                node_id,
-                msg: msg.into(),
-                lint_id: LintId::of(lint),
-                diagnostic: BuiltinLintDiag::Normal,
-            });
-        });
-    }
-
-    pub fn buffer_lint_with_diagnostic(
-        &self,
-        lint: &'static Lint,
-        span: impl Into<MultiSpan>,
-        node_id: NodeId,
-        msg: impl Into<DiagMessage>,
         diagnostic: BuiltinLintDiag,
     ) {
         self.buffered_lints.with_lock(|buffered_lints| {
             buffered_lints.push(BufferedEarlyLint {
                 span: span.into(),
                 node_id,
-                msg: msg.into(),
                 lint_id: LintId::of(lint),
                 diagnostic,
             });
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index db01bb9..a2872fc 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -1183,9 +1183,9 @@
             });
         }
     }
-    // Cannot mix and match sanitizers.
-    let mut sanitizer_iter = sess.opts.unstable_opts.sanitizer.into_iter();
-    if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) {
+
+    // Cannot mix and match mutually-exclusive sanitizers.
+    if let Some((first, second)) = sess.opts.unstable_opts.sanitizer.mutually_exclusive() {
         sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
             first: first.to_string(),
             second: second.to_string(),
@@ -1220,14 +1220,6 @@
         sess.dcx().emit_err(errors::SanitizerCfiRequiresSingleCodegenUnit);
     }
 
-    // LLVM CFI is incompatible with LLVM KCFI.
-    if sess.is_sanitizer_cfi_enabled() && sess.is_sanitizer_kcfi_enabled() {
-        sess.dcx().emit_err(errors::CannotMixAndMatchSanitizers {
-            first: "cfi".to_string(),
-            second: "kcfi".to_string(),
-        });
-    }
-
     // Canonical jump tables requires CFI.
     if sess.is_sanitizer_cfi_canonical_jump_tables_disabled() {
         if !sess.is_sanitizer_cfi_enabled() {
diff --git a/compiler/rustc_session/src/version.rs b/compiler/rustc_session/src/version.rs
index 39e4541..e244c77 100644
--- a/compiler/rustc_session/src/version.rs
+++ b/compiler/rustc_session/src/version.rs
@@ -1,5 +1,10 @@
 use rustc_macros::{current_rustc_version, Decodable, Encodable, HashStable_Generic};
-use std::fmt::{self, Display};
+use std::{
+    borrow::Cow,
+    fmt::{self, Display},
+};
+
+use rustc_errors::IntoDiagArg;
 
 #[derive(Encodable, Decodable, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[derive(HashStable_Generic)]
@@ -18,3 +23,9 @@
         write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)
     }
 }
+
+impl IntoDiagArg for RustcVersion {
+    fn into_diag_arg(self) -> rustc_errors::DiagArgValue {
+        rustc_errors::DiagArgValue::Str(Cow::Owned(self.to_string()))
+    }
+}
diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs
index 0893bc3..6b73c1e 100644
--- a/compiler/rustc_smir/src/rustc_internal/internal.rs
+++ b/compiler/rustc_smir/src/rustc_internal/internal.rs
@@ -216,7 +216,7 @@
         tcx.lift(rustc_ty::FnSig {
             inputs_and_output: tcx.mk_type_list(&self.inputs_and_output.internal(tables, tcx)),
             c_variadic: self.c_variadic,
-            unsafety: self.unsafety.internal(tables, tcx),
+            safety: self.safety.internal(tables, tcx),
             abi: self.abi.internal(tables, tcx),
         })
         .unwrap()
@@ -481,16 +481,15 @@
 }
 
 impl RustcInternal for Safety {
-    type T<'tcx> = rustc_hir::Unsafety;
+    type T<'tcx> = rustc_hir::Safety;
 
     fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> {
         match self {
-            Safety::Unsafe => rustc_hir::Unsafety::Unsafe,
-            Safety::Normal => rustc_hir::Unsafety::Normal,
+            Safety::Unsafe => rustc_hir::Safety::Unsafe,
+            Safety::Safe => rustc_hir::Safety::Safe,
         }
     }
 }
-
 impl RustcInternal for Span {
     type T<'tcx> = rustc_span::Span;
 
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
index 6fb1560..cbc3aae 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/abi.rs
@@ -256,10 +256,9 @@
             rustc_abi::Primitive::Int(length, signed) => {
                 Primitive::Int { length: length.stable(tables), signed: *signed }
             }
-            rustc_abi::Primitive::F16 => Primitive::Float { length: FloatLength::F16 },
-            rustc_abi::Primitive::F32 => Primitive::Float { length: FloatLength::F32 },
-            rustc_abi::Primitive::F64 => Primitive::Float { length: FloatLength::F64 },
-            rustc_abi::Primitive::F128 => Primitive::Float { length: FloatLength::F128 },
+            rustc_abi::Primitive::Float(length) => {
+                Primitive::Float { length: length.stable(tables) }
+            }
             rustc_abi::Primitive::Pointer(space) => Primitive::Pointer(space.stable(tables)),
         }
     }
@@ -287,6 +286,19 @@
     }
 }
 
+impl<'tcx> Stable<'tcx> for rustc_abi::Float {
+    type T = FloatLength;
+
+    fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
+        match self {
+            rustc_abi::Float::F16 => FloatLength::F16,
+            rustc_abi::Float::F32 => FloatLength::F32,
+            rustc_abi::Float::F64 => FloatLength::F64,
+            rustc_abi::Float::F128 => FloatLength::F128,
+        }
+    }
+}
+
 impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange {
     type T = WrappingRange;
 
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
index 452ab04..d89caab 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs
@@ -1,5 +1,6 @@
 //! Conversion of internal Rust compiler `mir` items to stable ones.
 
+use rustc_middle::bug;
 use rustc_middle::mir;
 use rustc_middle::mir::interpret::alloc_range;
 use rustc_middle::mir::mono::MonoItem;
@@ -183,16 +184,21 @@
                 op.stable(tables),
                 ty.stable(tables),
             ),
-            BinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::BinaryOp(
-                bin_op.stable(tables),
-                ops.0.stable(tables),
-                ops.1.stable(tables),
-            ),
-            CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp(
-                bin_op.stable(tables),
-                ops.0.stable(tables),
-                ops.1.stable(tables),
-            ),
+            BinaryOp(bin_op, ops) => {
+                if let Some(bin_op) = bin_op.overflowing_to_wrapping() {
+                    stable_mir::mir::Rvalue::CheckedBinaryOp(
+                        bin_op.stable(tables),
+                        ops.0.stable(tables),
+                        ops.1.stable(tables),
+                    )
+                } else {
+                    stable_mir::mir::Rvalue::BinaryOp(
+                        bin_op.stable(tables),
+                        ops.0.stable(tables),
+                        ops.1.stable(tables),
+                    )
+                }
+            }
             NullaryOp(null_op, ty) => {
                 stable_mir::mir::Rvalue::NullaryOp(null_op.stable(tables), ty.stable(tables))
             }
@@ -485,10 +491,13 @@
         match self {
             BinOp::Add => stable_mir::mir::BinOp::Add,
             BinOp::AddUnchecked => stable_mir::mir::BinOp::AddUnchecked,
+            BinOp::AddWithOverflow => bug!("AddWithOverflow should have been translated already"),
             BinOp::Sub => stable_mir::mir::BinOp::Sub,
             BinOp::SubUnchecked => stable_mir::mir::BinOp::SubUnchecked,
+            BinOp::SubWithOverflow => bug!("AddWithOverflow should have been translated already"),
             BinOp::Mul => stable_mir::mir::BinOp::Mul,
             BinOp::MulUnchecked => stable_mir::mir::BinOp::MulUnchecked,
+            BinOp::MulWithOverflow => bug!("AddWithOverflow should have been translated already"),
             BinOp::Div => stable_mir::mir::BinOp::Div,
             BinOp::Rem => stable_mir::mir::BinOp::Rem,
             BinOp::BitXor => stable_mir::mir::BinOp::BitXor,
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
index 41b0a84..736378a 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/mod.rs
@@ -9,12 +9,12 @@
 mod mir;
 mod ty;
 
-impl<'tcx> Stable<'tcx> for rustc_hir::Unsafety {
+impl<'tcx> Stable<'tcx> for rustc_hir::Safety {
     type T = stable_mir::mir::Safety;
     fn stable(&self, _: &mut Tables<'_>) -> Self::T {
         match self {
-            rustc_hir::Unsafety::Unsafe => stable_mir::mir::Safety::Unsafe,
-            rustc_hir::Unsafety::Normal => stable_mir::mir::Safety::Normal,
+            rustc_hir::Safety::Unsafe => stable_mir::mir::Safety::Unsafe,
+            rustc_hir::Safety::Safe => stable_mir::mir::Safety::Safe,
         }
     }
 }
diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
index 4abf991..be20924 100644
--- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
+++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs
@@ -9,7 +9,7 @@
 
 use crate::rustc_smir::{alloc, Stable, Tables};
 
-impl<'tcx> Stable<'tcx> for ty::AliasKind {
+impl<'tcx> Stable<'tcx> for ty::AliasTyKind {
     type T = stable_mir::ty::AliasKind;
     fn stable(&self, _: &mut Tables<'_>) -> Self::T {
         match self {
@@ -29,6 +29,14 @@
     }
 }
 
+impl<'tcx> Stable<'tcx> for ty::AliasTerm<'tcx> {
+    type T = stable_mir::ty::AliasTerm;
+    fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
+        let ty::AliasTerm { args, def_id, .. } = self;
+        stable_mir::ty::AliasTerm { def_id: tables.alias_def(*def_id), args: args.stable(tables) }
+    }
+}
+
 impl<'tcx> Stable<'tcx> for ty::DynKind {
     type T = stable_mir::ty::DynKind;
 
@@ -104,8 +112,8 @@
         match self {
             PointerCoercion::ReifyFnPointer => stable_mir::mir::PointerCoercion::ReifyFnPointer,
             PointerCoercion::UnsafeFnPointer => stable_mir::mir::PointerCoercion::UnsafeFnPointer,
-            PointerCoercion::ClosureFnPointer(unsafety) => {
-                stable_mir::mir::PointerCoercion::ClosureFnPointer(unsafety.stable(tables))
+            PointerCoercion::ClosureFnPointer(safety) => {
+                stable_mir::mir::PointerCoercion::ClosureFnPointer(safety.stable(tables))
             }
             PointerCoercion::MutToConstPointer => {
                 stable_mir::mir::PointerCoercion::MutToConstPointer
@@ -207,7 +215,7 @@
         FnSig {
             inputs_and_output: self.inputs_and_output.iter().map(|ty| ty.stable(tables)).collect(),
             c_variadic: self.c_variadic,
-            unsafety: self.unsafety.stable(tables),
+            safety: self.safety.stable(tables),
             abi: self.abi.stable(tables),
         }
     }
@@ -491,12 +499,13 @@
 
         TraitDecl {
             def_id: tables.trait_def(self.def_id),
-            unsafety: self.unsafety.stable(tables),
+            safety: self.safety.stable(tables),
             paren_sugar: self.paren_sugar,
             has_auto_impl: self.has_auto_impl,
             is_marker: self.is_marker,
             is_coinductive: self.is_coinductive,
             skip_array_during_method_dispatch: self.skip_array_during_method_dispatch,
+            skip_boxed_slice_during_method_dispatch: self.skip_boxed_slice_during_method_dispatch,
             specialization_kind: self.specialization_kind.stable(tables),
             must_implement_one_of: self
                 .must_implement_one_of
@@ -523,7 +532,7 @@
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
         use stable_mir::ty::Generics;
 
-        let params: Vec<_> = self.params.iter().map(|param| param.stable(tables)).collect();
+        let params: Vec<_> = self.own_params.iter().map(|param| param.stable(tables)).collect();
         let param_def_id_to_index =
             params.iter().map(|param| (param.def_id, param.index)).collect();
 
@@ -698,12 +707,11 @@
     }
 }
 
-impl<'tcx, A, B, U, V> Stable<'tcx> for ty::OutlivesPredicate<A, B>
+impl<'tcx, T> Stable<'tcx> for ty::OutlivesPredicate<'tcx, T>
 where
-    A: Stable<'tcx, T = U>,
-    B: Stable<'tcx, T = V>,
+    T: Stable<'tcx>,
 {
-    type T = stable_mir::ty::OutlivesPredicate<U, V>;
+    type T = stable_mir::ty::OutlivesPredicate<T::T, Region>;
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
         let ty::OutlivesPredicate(a, b) = self;
@@ -715,9 +723,9 @@
     type T = stable_mir::ty::ProjectionPredicate;
 
     fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
-        let ty::ProjectionPredicate { projection_ty, term } = self;
+        let ty::ProjectionPredicate { projection_term, term } = self;
         stable_mir::ty::ProjectionPredicate {
-            projection_ty: projection_ty.stable(tables),
+            projection_term: projection_term.stable(tables),
             term: term.unpack().stable(tables),
         }
     }
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index d41059e..ace4dff 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -782,6 +782,8 @@
         explicit_tail_calls,
         export_name,
         expr,
+        expr_2021,
+        expr_fragment_specifier_2024,
         extended_key_value_attributes,
         extended_varargs_abi_support,
         extern_absolute_paths,
@@ -928,6 +930,7 @@
         global_alloc_ty,
         global_allocator,
         global_asm,
+        global_registration,
         globs,
         gt,
         half_open_range_patterns,
@@ -1630,7 +1633,7 @@
         rustc_reservation_impl,
         rustc_safe_intrinsic,
         rustc_serialize,
-        rustc_skip_array_during_method_dispatch,
+        rustc_skip_during_method_dispatch,
         rustc_specialization_trait,
         rustc_std_internal_symbol,
         rustc_strict_coherence,
@@ -1679,6 +1682,7 @@
         simd_cast_ptr,
         simd_ceil,
         simd_ctlz,
+        simd_ctpop,
         simd_cttz,
         simd_div,
         simd_eq,
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index 5cdfb77..57b1542 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -319,11 +319,10 @@
             ty::Uint(UintTy::U64) => "y",
             ty::Uint(UintTy::U128) => "o",
             ty::Uint(UintTy::Usize) => "j",
-            // FIXME(f16_f128): update these once `rustc-demangle` supports the new types
-            ty::Float(FloatTy::F16) => unimplemented!("f16_f128"),
+            ty::Float(FloatTy::F16) => "C3f16",
             ty::Float(FloatTy::F32) => "f",
             ty::Float(FloatTy::F64) => "d",
-            ty::Float(FloatTy::F128) => unimplemented!("f16_f128"),
+            ty::Float(FloatTy::F128) => "C4f128",
             ty::Never => "z",
 
             // Placeholders (should be demangled as `_`).
@@ -425,7 +424,7 @@
             ty::FnPtr(sig) => {
                 self.push("F");
                 self.in_binder(&sig, |cx, sig| {
-                    if sig.unsafety == hir::Unsafety::Unsafe {
+                    if sig.safety == hir::Safety::Unsafe {
                         cx.push("U");
                     }
                     match sig.abi {
@@ -630,8 +629,7 @@
                         let pointee_ty = ct
                             .ty()
                             .builtin_deref(true)
-                            .expect("tried to dereference on non-ptr type")
-                            .ty;
+                            .expect("tried to dereference on non-ptr type");
                         // FIXME(const_generics): add an assert that we only do this for valtrees.
                         let dereferenced_const = self.tcx.mk_ct_from_kind(ct.kind(), pointee_ty);
                         dereferenced_const.print(self)?;
diff --git a/compiler/rustc_target/src/abi/call/loongarch.rs b/compiler/rustc_target/src/abi/call/loongarch.rs
index 943b12a..893818a 100644
--- a/compiler/rustc_target/src/abi/call/loongarch.rs
+++ b/compiler/rustc_target/src/abi/call/loongarch.rs
@@ -59,7 +59,7 @@
                     _ => return Err(CannotUseFpConv),
                 }
             }
-            abi::F16 | abi::F32 | abi::F64 | abi::F128 => {
+            abi::Float(_) => {
                 if arg_layout.size.bits() > flen {
                     return Err(CannotUseFpConv);
                 }
diff --git a/compiler/rustc_target/src/abi/call/mips64.rs b/compiler/rustc_target/src/abi/call/mips64.rs
index b2a2c34..5b52ebb 100644
--- a/compiler/rustc_target/src/abi/call/mips64.rs
+++ b/compiler/rustc_target/src/abi/call/mips64.rs
@@ -26,8 +26,8 @@
 {
     match ret.layout.field(cx, i).abi {
         abi::Abi::Scalar(scalar) => match scalar.primitive() {
-            abi::F32 => Some(Reg::f32()),
-            abi::F64 => Some(Reg::f64()),
+            abi::Float(abi::F32) => Some(Reg::f32()),
+            abi::Float(abi::F64) => Some(Reg::f64()),
             _ => None,
         },
         _ => None,
@@ -110,7 +110,7 @@
 
                 // We only care about aligned doubles
                 if let abi::Abi::Scalar(scalar) = field.abi {
-                    if let abi::F64 = scalar.primitive() {
+                    if scalar.primitive() == abi::Float(abi::F64) {
                         if offset.is_aligned(dl.f64_align.abi) {
                             // Insert enough integers to cover [last_offset, offset)
                             assert!(last_offset.is_aligned(dl.f64_align.abi));
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 3ddea42..fc79c92 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -443,7 +443,7 @@
             Abi::Scalar(scalar) => {
                 let kind = match scalar.primitive() {
                     abi::Int(..) | abi::Pointer(_) => RegKind::Integer,
-                    abi::F16 | abi::F32 | abi::F64 | abi::F128 => RegKind::Float,
+                    abi::Float(_) => RegKind::Float,
                 };
                 Ok(HomogeneousAggregate::Homogeneous(Reg { kind, size: self.size }))
             }
@@ -779,16 +779,21 @@
 /// Metadata describing how the arguments to a native function
 /// should be passed in order to respect the native ABI.
 ///
+/// The signature represented by this type may not match the MIR function signature.
+/// Certain attributes, like `#[track_caller]` can introduce additional arguments, which are present in [`FnAbi`], but not in `FnSig`.
+/// While this difference is rarely relevant, it should still be kept in mind.
+///
 /// I will do my best to describe this structure, but these
 /// comments are reverse-engineered and may be inaccurate. -NDM
 #[derive(Clone, PartialEq, Eq, Hash, HashStable_Generic)]
 pub struct FnAbi<'a, Ty> {
-    /// The LLVM types of each argument.
+    /// The type, layout, and information about how each argument is passed.
     pub args: Box<[ArgAbi<'a, Ty>]>,
 
-    /// LLVM return type.
+    /// The layout, type, and the way a value is returned from this function.
     pub ret: ArgAbi<'a, Ty>,
 
+    /// Marks this function as variadic (accepting a variable number of arguments).
     pub c_variadic: bool,
 
     /// The count of non-variadic arguments.
@@ -796,9 +801,9 @@
     /// Should only be different from args.len() when c_variadic is true.
     /// This can be used to know whether an argument is variadic or not.
     pub fixed_count: u32,
-
+    /// The calling convention of this function.
     pub conv: Conv,
-
+    /// Indicates if an unwind may happen across a call to this function.
     pub can_unwind: bool,
 }
 
diff --git a/compiler/rustc_target/src/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs
index 5d4b3a9..84f13f8 100644
--- a/compiler/rustc_target/src/abi/call/riscv.rs
+++ b/compiler/rustc_target/src/abi/call/riscv.rs
@@ -65,7 +65,7 @@
                     _ => return Err(CannotUseFpConv),
                 }
             }
-            abi::F16 | abi::F32 | abi::F64 | abi::F128 => {
+            abi::Float(_) => {
                 if arg_layout.size.bits() > flen {
                     return Err(CannotUseFpConv);
                 }
diff --git a/compiler/rustc_target/src/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs
index acdcd5c..c0952130 100644
--- a/compiler/rustc_target/src/abi/call/sparc64.rs
+++ b/compiler/rustc_target/src/abi/call/sparc64.rs
@@ -20,7 +20,7 @@
 {
     let dl = cx.data_layout();
 
-    if !matches!(scalar.primitive(), abi::F32 | abi::F64) {
+    if !matches!(scalar.primitive(), abi::Float(abi::F32 | abi::F64)) {
         return data;
     }
 
@@ -56,7 +56,7 @@
         return data;
     }
 
-    if scalar.primitive() == abi::F32 {
+    if scalar.primitive() == abi::Float(abi::F32) {
         data.arg_attribute = ArgAttribute::InReg;
         data.prefix[data.prefix_index] = Some(Reg::f32());
         data.last_offset = offset + Reg::f32().size;
@@ -80,14 +80,14 @@
 {
     data = arg_scalar(cx, scalar1, offset, data);
     match (scalar1.primitive(), scalar2.primitive()) {
-        (abi::F32, _) => offset += Reg::f32().size,
-        (_, abi::F64) => offset += Reg::f64().size,
+        (abi::Float(abi::F32), _) => offset += Reg::f32().size,
+        (_, abi::Float(abi::F64)) => offset += Reg::f64().size,
         (abi::Int(i, _signed), _) => offset += i.size(),
         (abi::Pointer(_), _) => offset += Reg::i64().size,
         _ => {}
     }
 
-    if (offset.bytes() % 4) != 0 && matches!(scalar2.primitive(), abi::F32 | abi::F64) {
+    if (offset.bytes() % 4) != 0 && matches!(scalar2.primitive(), abi::Float(abi::F32 | abi::F64)) {
         offset += Size::from_bytes(4 - (offset.bytes() % 4));
     }
     data = arg_scalar(cx, scalar2, offset, data);
diff --git a/compiler/rustc_target/src/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs
index f3208fe..fcd7124 100644
--- a/compiler/rustc_target/src/abi/call/x86_64.rs
+++ b/compiler/rustc_target/src/abi/call/x86_64.rs
@@ -51,7 +51,7 @@
 
             Abi::Scalar(scalar) => match scalar.primitive() {
                 abi::Int(..) | abi::Pointer(_) => Class::Int,
-                abi::F16 | abi::F32 | abi::F64 | abi::F128 => Class::Sse,
+                abi::Float(_) => Class::Sse,
             },
 
             Abi::Vector { .. } => Class::Sse,
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 24e49ff..666efd9 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -1,4 +1,5 @@
 use rustc_data_structures::intern::Interned;
+pub use Float::*;
 pub use Integer::*;
 pub use Primitive::*;
 
@@ -11,7 +12,8 @@
 
 pub mod call;
 
-pub use rustc_abi::*;
+// Explicitly import `Float` to avoid ambiguity with `Primitive::Float`.
+pub use rustc_abi::{Float, *};
 
 impl ToJson for Endian {
     fn to_json(&self) -> Json {
@@ -207,7 +209,7 @@
         C: HasDataLayout,
     {
         match self.abi {
-            Abi::Scalar(scalar) => matches!(scalar.primitive(), F32 | F64),
+            Abi::Scalar(scalar) => matches!(scalar.primitive(), Float(F32 | F64)),
             Abi::Aggregate { .. } => {
                 if self.fields.count() == 1 && self.fields.offset(0).bytes() == 0 {
                     self.field(cx, 0).is_single_fp_element(cx)
diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs
index 84d7930..46c83be 100644
--- a/compiler/rustc_target/src/lib.rs
+++ b/compiler/rustc_target/src/lib.rs
@@ -7,16 +7,17 @@
 //! more 'stuff' here in the future. It does not have a dependency on
 //! LLVM.
 
+// tidy-alphabetical-start
+#![allow(internal_features)]
 #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
 #![doc(rust_logo)]
-#![feature(min_exhaustive_patterns)]
-#![feature(rustdoc_internals)]
 #![feature(assert_matches)]
 #![feature(iter_intersperse)]
 #![feature(let_chains)]
+#![feature(min_exhaustive_patterns)]
 #![feature(rustc_attrs)]
-#![feature(step_trait)]
-#![allow(internal_features)]
+#![feature(rustdoc_internals)]
+// tidy-alphabetical-end
 
 use std::path::{Path, PathBuf};
 
diff --git a/compiler/rustc_target/src/spec/base/apple/mod.rs b/compiler/rustc_target/src/spec/base/apple/mod.rs
index d667bad..0554200 100644
--- a/compiler/rustc_target/src/spec/base/apple/mod.rs
+++ b/compiler/rustc_target/src/spec/base/apple/mod.rs
@@ -17,14 +17,9 @@
     Arm64e,
     Arm64_32,
     I386,
-    I386_sim,
     I686,
     X86_64,
     X86_64h,
-    X86_64_sim,
-    X86_64_macabi,
-    Arm64_macabi,
-    Arm64_sim,
 }
 
 impl Arch {
@@ -32,12 +27,12 @@
         match self {
             Armv7k => "armv7k",
             Armv7s => "armv7s",
-            Arm64 | Arm64_macabi | Arm64_sim => "arm64",
+            Arm64 => "arm64",
             Arm64e => "arm64e",
             Arm64_32 => "arm64_32",
-            I386 | I386_sim => "i386",
+            I386 => "i386",
             I686 => "i686",
-            X86_64 | X86_64_sim | X86_64_macabi => "x86_64",
+            X86_64 => "x86_64",
             X86_64h => "x86_64h",
         }
     }
@@ -45,61 +40,70 @@
     pub fn target_arch(self) -> Cow<'static, str> {
         Cow::Borrowed(match self {
             Armv7k | Armv7s => "arm",
-            Arm64 | Arm64e | Arm64_32 | Arm64_macabi | Arm64_sim => "aarch64",
-            I386 | I386_sim | I686 => "x86",
-            X86_64 | X86_64_sim | X86_64_macabi | X86_64h => "x86_64",
+            Arm64 | Arm64e | Arm64_32 => "aarch64",
+            I386 | I686 => "x86",
+            X86_64 | X86_64h => "x86_64",
         })
     }
 
-    fn target_abi(self) -> &'static str {
-        match self {
-            Armv7k | Armv7s | Arm64 | Arm64e | Arm64_32 | I386 | I686 | X86_64 | X86_64h => "",
-            X86_64_macabi | Arm64_macabi => "macabi",
-            I386_sim | Arm64_sim | X86_64_sim => "sim",
-        }
-    }
-
-    fn target_cpu(self) -> &'static str {
+    fn target_cpu(self, abi: TargetAbi) -> &'static str {
         match self {
             Armv7k => "cortex-a8",
             Armv7s => "swift", // iOS 10 is only supported on iPhone 5 or higher.
-            Arm64 => "apple-a7",
+            Arm64 => match abi {
+                TargetAbi::Normal => "apple-a7",
+                TargetAbi::Simulator => "apple-a12",
+                TargetAbi::MacCatalyst => "apple-a12",
+            },
             Arm64e => "apple-a12",
             Arm64_32 => "apple-s4",
             // Only macOS 10.12+ is supported, which means
             // all x86_64/x86 CPUs must be running at least penryn
             // https://github.com/llvm/llvm-project/blob/01f924d0e37a5deae51df0d77e10a15b63aa0c0f/clang/lib/Driver/ToolChains/Arch/X86.cpp#L79-L82
-            I386 | I386_sim | I686 => "penryn",
-            X86_64 | X86_64_sim => "penryn",
-            X86_64_macabi => "penryn",
+            I386 | I686 => "penryn",
+            X86_64 => "penryn",
             // Note: `core-avx2` is slightly more advanced than `x86_64h`, see
             // comments (and disabled features) in `x86_64h_apple_darwin` for
             // details. It is a higher baseline then `penryn` however.
             X86_64h => "core-avx2",
-            Arm64_macabi => "apple-a12",
-            Arm64_sim => "apple-a12",
         }
     }
 
     fn stack_probes(self) -> StackProbeType {
         match self {
             Armv7k | Armv7s => StackProbeType::None,
-            Arm64 | Arm64e | Arm64_32 | I386 | I386_sim | I686 | X86_64 | X86_64h | X86_64_sim
-            | X86_64_macabi | Arm64_macabi | Arm64_sim => StackProbeType::Inline,
+            Arm64 | Arm64e | Arm64_32 | I386 | I686 | X86_64 | X86_64h => StackProbeType::Inline,
         }
     }
 }
 
-fn pre_link_args(os: &'static str, arch: Arch, abi: &'static str) -> LinkArgs {
+#[derive(Copy, Clone, PartialEq)]
+pub enum TargetAbi {
+    Normal,
+    Simulator,
+    MacCatalyst,
+}
+
+impl TargetAbi {
+    fn target_abi(self) -> &'static str {
+        match self {
+            Self::Normal => "",
+            Self::MacCatalyst => "macabi",
+            Self::Simulator => "sim",
+        }
+    }
+}
+
+fn pre_link_args(os: &'static str, arch: Arch, abi: TargetAbi) -> LinkArgs {
     let platform_name: StaticCow<str> = match abi {
-        "sim" => format!("{os}-simulator").into(),
-        "macabi" => "mac-catalyst".into(),
-        _ => os.into(),
+        TargetAbi::Normal => os.into(),
+        TargetAbi::Simulator => format!("{os}-simulator").into(),
+        TargetAbi::MacCatalyst => "mac-catalyst".into(),
     };
 
     let min_version: StaticCow<str> = {
         let (major, minor) = match os {
-            "ios" => ios_deployment_target(arch, abi),
+            "ios" => ios_deployment_target(arch, abi.target_abi()),
             "tvos" => tvos_deployment_target(),
             "watchos" => watchos_deployment_target(),
             "visionos" => visionos_deployment_target(),
@@ -119,7 +123,7 @@
         LinkerFlavor::Darwin(Cc::No, Lld::No),
         [platform_name, min_version, sdk_version].into_iter(),
     );
-    if abi != "macabi" {
+    if abi != TargetAbi::MacCatalyst {
         add_link_args(
             &mut args,
             LinkerFlavor::Darwin(Cc::Yes, Lld::No),
@@ -136,13 +140,11 @@
     args
 }
 
-pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
-    let abi = arch.target_abi();
-
+pub fn opts(os: &'static str, arch: Arch, abi: TargetAbi) -> TargetOptions {
     TargetOptions {
-        abi: abi.into(),
+        abi: abi.target_abi().into(),
         os: os.into(),
-        cpu: arch.target_cpu().into(),
+        cpu: arch.target_cpu(abi).into(),
         link_env_remove: link_env_remove(os),
         vendor: "apple".into(),
         linker_flavor: LinkerFlavor::Darwin(Cc::Yes, Lld::No),
@@ -263,14 +265,14 @@
 
 fn macos_default_deployment_target(arch: Arch) -> (u32, u32) {
     match arch {
-        // Note: Arm64_sim is not included since macOS has no simulator.
-        Arm64 | Arm64e | Arm64_macabi => (11, 0),
+        Arm64 | Arm64e => (11, 0),
         _ => (10, 12),
     }
 }
 
 fn macos_deployment_target(arch: Arch) -> (u32, u32) {
     // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+    // Note: If bumping this version, remember to update it in the rustc/platform-support docs.
     from_set_deployment_target("MACOSX_DEPLOYMENT_TARGET")
         .unwrap_or_else(|| macos_default_deployment_target(arch))
 }
@@ -319,6 +321,7 @@
 
 fn ios_deployment_target(arch: Arch, abi: &str) -> (u32, u32) {
     // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+    // Note: If bumping this version, remember to update it in the rustc/platform-support docs.
     let (major, minor) = match (arch, abi) {
         (Arm64e, _) => (14, 0),
         // Mac Catalyst defaults to 13.1 in Clang.
@@ -351,6 +354,7 @@
 
 fn tvos_deployment_target() -> (u32, u32) {
     // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+    // Note: If bumping this version, remember to update it in the rustc platform-support docs.
     from_set_deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((10, 0))
 }
 
@@ -366,6 +370,7 @@
 
 fn watchos_deployment_target() -> (u32, u32) {
     // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+    // Note: If bumping this version, remember to update it in the rustc platform-support docs.
     from_set_deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0))
 }
 
@@ -381,6 +386,7 @@
 
 fn visionos_deployment_target() -> (u32, u32) {
     // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+    // Note: If bumping this version, remember to update it in the rustc platform-support docs.
     from_set_deployment_target("XROS_DEPLOYMENT_TARGET").unwrap_or((1, 0))
 }
 
diff --git a/compiler/rustc_target/src/spec/base/windows_gnu.rs b/compiler/rustc_target/src/spec/base/windows_gnu.rs
index 25f02dc..1357de2 100644
--- a/compiler/rustc_target/src/spec/base/windows_gnu.rs
+++ b/compiler/rustc_target/src/spec/base/windows_gnu.rs
@@ -40,6 +40,9 @@
         //
         // See https://github.com/rust-lang/rust/pull/47483 for some more details.
         "-lmsvcrt",
+        // Math functions missing in MSVCRT (they are present in UCRT) require
+        // this dependency cycle: `libmingwex.a` -> `libmsvcrt.a` -> `libmingwex.a`.
+        "-lmingwex",
         "-luser32",
         "-lkernel32",
     ];
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index cbb248a..83ee63e 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -603,19 +603,6 @@
         self == LinkSelfContainedDefault::False
     }
 
-    /// Returns whether the target spec explicitly requests self-contained linking, i.e. not via
-    /// inference.
-    pub fn is_linker_enabled(self) -> bool {
-        match self {
-            LinkSelfContainedDefault::True => true,
-            LinkSelfContainedDefault::False => false,
-            LinkSelfContainedDefault::WithComponents(c) => {
-                c.contains(LinkSelfContainedComponents::LINKER)
-            }
-            _ => false,
-        }
-    }
-
     /// Returns the key to use when serializing the setting to json:
     /// - individual components in a `link-self-contained` object value
     /// - the other variants as a backwards-compatible `crt-objects-fallback` string
@@ -625,6 +612,12 @@
             _ => "crt-objects-fallback",
         }
     }
+
+    /// Creates a `LinkSelfContainedDefault` enabling the self-contained linker for target specs
+    /// (the equivalent of `-Clink-self-contained=+linker` on the CLI).
+    pub fn with_linker() -> LinkSelfContainedDefault {
+        LinkSelfContainedDefault::WithComponents(LinkSelfContainedComponents::LINKER)
+    }
 }
 
 bitflags::bitflags! {
@@ -1324,6 +1317,34 @@
 rustc_data_structures::external_bitflags_debug! { SanitizerSet }
 
 impl SanitizerSet {
+    // Taken from LLVM's sanitizer compatibility logic:
+    // https://github.com/llvm/llvm-project/blob/release/18.x/clang/lib/Driver/SanitizerArgs.cpp#L512
+    const MUTUALLY_EXCLUSIVE: &'static [(SanitizerSet, SanitizerSet)] = &[
+        (SanitizerSet::ADDRESS, SanitizerSet::MEMORY),
+        (SanitizerSet::ADDRESS, SanitizerSet::THREAD),
+        (SanitizerSet::ADDRESS, SanitizerSet::HWADDRESS),
+        (SanitizerSet::ADDRESS, SanitizerSet::MEMTAG),
+        (SanitizerSet::ADDRESS, SanitizerSet::KERNELADDRESS),
+        (SanitizerSet::ADDRESS, SanitizerSet::SAFESTACK),
+        (SanitizerSet::LEAK, SanitizerSet::MEMORY),
+        (SanitizerSet::LEAK, SanitizerSet::THREAD),
+        (SanitizerSet::LEAK, SanitizerSet::KERNELADDRESS),
+        (SanitizerSet::LEAK, SanitizerSet::SAFESTACK),
+        (SanitizerSet::MEMORY, SanitizerSet::THREAD),
+        (SanitizerSet::MEMORY, SanitizerSet::HWADDRESS),
+        (SanitizerSet::MEMORY, SanitizerSet::KERNELADDRESS),
+        (SanitizerSet::MEMORY, SanitizerSet::SAFESTACK),
+        (SanitizerSet::THREAD, SanitizerSet::HWADDRESS),
+        (SanitizerSet::THREAD, SanitizerSet::KERNELADDRESS),
+        (SanitizerSet::THREAD, SanitizerSet::SAFESTACK),
+        (SanitizerSet::HWADDRESS, SanitizerSet::MEMTAG),
+        (SanitizerSet::HWADDRESS, SanitizerSet::KERNELADDRESS),
+        (SanitizerSet::HWADDRESS, SanitizerSet::SAFESTACK),
+        (SanitizerSet::CFI, SanitizerSet::KCFI),
+        (SanitizerSet::MEMTAG, SanitizerSet::KERNELADDRESS),
+        (SanitizerSet::KERNELADDRESS, SanitizerSet::SAFESTACK),
+    ];
+
     /// Return sanitizer's name
     ///
     /// Returns none if the flags is a set of sanitizers numbering not exactly one.
@@ -1344,6 +1365,13 @@
             _ => return None,
         })
     }
+
+    pub fn mutually_exclusive(self) -> Option<(SanitizerSet, SanitizerSet)> {
+        Self::MUTUALLY_EXCLUSIVE
+            .into_iter()
+            .find(|&(a, b)| self.contains(*a) && self.contains(*b))
+            .copied()
+    }
 }
 
 /// Formats a sanitizer set as a comma separated list of sanitizers' names.
@@ -1787,6 +1815,9 @@
     ("aarch64-unknown-linux-ohos", aarch64_unknown_linux_ohos),
     ("armv7-unknown-linux-ohos", armv7_unknown_linux_ohos),
     ("x86_64-unknown-linux-ohos", x86_64_unknown_linux_ohos),
+
+    ("x86_64-unknown-linux-none", x86_64_unknown_linux_none),
+
 }
 
 /// Cow-Vec-Str: Cow<'static, [Cow<'static, str>]>
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
index c59c0ee..4e29641 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_darwin.rs
@@ -1,9 +1,9 @@
-use crate::spec::base::apple::{macos_llvm_target, opts, Arch};
+use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi};
 use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
     let arch = Arch::Arm64;
-    let mut base = opts("macos", arch);
+    let mut base = opts("macos", arch, TargetAbi::Normal);
     base.cpu = "apple-m1".into();
     base.max_atomic_width = Some(128);
 
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs
index 4bbd962..2065568 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios.rs
@@ -1,9 +1,9 @@
-use crate::spec::base::apple::{ios_llvm_target, opts, Arch};
+use crate::spec::base::apple::{ios_llvm_target, opts, Arch, TargetAbi};
 use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
     let arch = Arch::Arm64;
-    let mut base = opts("ios", arch);
+    let mut base = opts("ios", arch, TargetAbi::Normal);
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs
index af413e8..4c008f7 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_macabi.rs
@@ -1,9 +1,9 @@
-use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch};
+use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch, TargetAbi};
 use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let arch = Arch::Arm64_macabi;
-    let mut base = opts("ios", arch);
+    let arch = Arch::Arm64;
+    let mut base = opts("ios", arch, TargetAbi::MacCatalyst);
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD;
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs
index 2c1dd41..4a63abd 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_ios_sim.rs
@@ -1,9 +1,9 @@
-use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch};
+use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch, TargetAbi};
 use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let arch = Arch::Arm64_sim;
-    let mut base = opts("ios", arch);
+    let arch = Arch::Arm64;
+    let mut base = opts("ios", arch, TargetAbi::Simulator);
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs
index b5623c8..3310e6c 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos.rs
@@ -1,4 +1,4 @@
-use crate::spec::base::apple::{opts, tvos_llvm_target, Arch};
+use crate::spec::base::apple::{opts, tvos_llvm_target, Arch, TargetAbi};
 use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
@@ -18,7 +18,7 @@
             features: "+neon,+fp-armv8,+apple-a7".into(),
             max_atomic_width: Some(128),
             frame_pointer: FramePointer::NonLeaf,
-            ..opts("tvos", arch)
+            ..opts("tvos", arch, TargetAbi::Normal)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs
index cf4bbb1..b901c66 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_tvos_sim.rs
@@ -1,8 +1,8 @@
-use crate::spec::base::apple::{opts, tvos_sim_llvm_target, Arch};
+use crate::spec::base::apple::{opts, tvos_sim_llvm_target, Arch, TargetAbi};
 use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let arch = Arch::Arm64_sim;
+    let arch = Arch::Arm64;
     Target {
         llvm_target: tvos_sim_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
@@ -18,7 +18,7 @@
             features: "+neon,+fp-armv8,+apple-a7".into(),
             max_atomic_width: Some(128),
             frame_pointer: FramePointer::NonLeaf,
-            ..opts("tvos", arch)
+            ..opts("tvos", arch, TargetAbi::Simulator)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs
index bacc467..b0798e5 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos.rs
@@ -1,9 +1,9 @@
-use crate::spec::base::apple::{opts, visionos_llvm_target, Arch};
+use crate::spec::base::apple::{opts, visionos_llvm_target, Arch, TargetAbi};
 use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
     let arch = Arch::Arm64;
-    let mut base = opts("visionos", arch);
+    let mut base = opts("visionos", arch, TargetAbi::Normal);
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs
index 99df73c..7b2d2b6 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_visionos_sim.rs
@@ -1,9 +1,9 @@
-use crate::spec::base::apple::{opts, visionos_sim_llvm_target, Arch};
+use crate::spec::base::apple::{opts, visionos_sim_llvm_target, Arch, TargetAbi};
 use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let arch = Arch::Arm64_sim;
-    let mut base = opts("visionos", arch);
+    let arch = Arch::Arm64;
+    let mut base = opts("visionos", arch, TargetAbi::Simulator);
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs
index 3fbb780..a00a97a 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos.rs
@@ -1,8 +1,8 @@
-use crate::spec::base::apple::{opts, Arch};
+use crate::spec::base::apple::{opts, Arch, TargetAbi};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let base = opts("watchos", Arch::Arm64);
+    let base = opts("watchos", Arch::Arm64, TargetAbi::Normal);
     Target {
         llvm_target: "aarch64-apple-watchos".into(),
         metadata: crate::spec::TargetMetadata {
diff --git a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs
index c13615b..e2f80b7 100644
--- a/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs
+++ b/compiler/rustc_target/src/spec/targets/aarch64_apple_watchos_sim.rs
@@ -1,8 +1,8 @@
-use crate::spec::base::apple::{opts, watchos_sim_llvm_target, Arch};
+use crate::spec::base::apple::{opts, watchos_sim_llvm_target, Arch, TargetAbi};
 use crate::spec::{FramePointer, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let arch = Arch::Arm64_sim;
+    let arch = Arch::Arm64;
     Target {
         // Clang automatically chooses a more specific target based on
         // WATCHOS_DEPLOYMENT_TARGET.
@@ -22,7 +22,7 @@
             features: "+neon,+fp-armv8,+apple-a7".into(),
             max_atomic_width: Some(128),
             frame_pointer: FramePointer::NonLeaf,
-            ..opts("watchos", arch)
+            ..opts("watchos", arch, TargetAbi::Simulator)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs
index 38166a8..3ca8c99 100644
--- a/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs
+++ b/compiler/rustc_target/src/spec/targets/arm64_32_apple_watchos.rs
@@ -1,9 +1,9 @@
-use crate::spec::base::apple::{opts, watchos_llvm_target, Arch};
+use crate::spec::base::apple::{opts, watchos_llvm_target, Arch, TargetAbi};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let arch = Arch::Arm64_32;
-    let base = opts("watchos", arch);
+    let base = opts("watchos", arch, TargetAbi::Normal);
     Target {
         llvm_target: watchos_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs
index cf69309..90be518 100644
--- a/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_darwin.rs
@@ -1,9 +1,9 @@
-use crate::spec::base::apple::{macos_llvm_target, opts, Arch};
+use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi};
 use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
     let arch = Arch::Arm64e;
-    let mut base = opts("macos", arch);
+    let mut base = opts("macos", arch, TargetAbi::Normal);
     base.cpu = "apple-m1".into();
     base.max_atomic_width = Some(128);
 
diff --git a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs
index bff4074..56470d2 100644
--- a/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/arm64e_apple_ios.rs
@@ -1,9 +1,9 @@
-use crate::spec::base::apple::{ios_llvm_target, opts, Arch};
+use crate::spec::base::apple::{ios_llvm_target, opts, Arch, TargetAbi};
 use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
     let arch = Arch::Arm64e;
-    let mut base = opts("ios", arch);
+    let mut base = opts("ios", arch, TargetAbi::Normal);
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs
index 42ad9e0..5c675c2 100644
--- a/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7k_apple_watchos.rs
@@ -1,4 +1,4 @@
-use crate::spec::base::apple::{opts, Arch};
+use crate::spec::base::apple::{opts, Arch, TargetAbi};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
@@ -19,7 +19,7 @@
             max_atomic_width: Some(64),
             dynamic_linking: false,
             position_independent_executables: true,
-            ..opts("watchos", arch)
+            ..opts("watchos", arch, TargetAbi::Normal)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs
index 40e5fc3..4dd475e 100644
--- a/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/armv7s_apple_ios.rs
@@ -1,4 +1,4 @@
-use crate::spec::base::apple::{ios_llvm_target, opts, Arch};
+use crate::spec::base::apple::{ios_llvm_target, opts, Arch, TargetAbi};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
@@ -17,7 +17,7 @@
         options: TargetOptions {
             features: "+v7,+vfp4,+neon".into(),
             max_atomic_width: Some(64),
-            ..opts("ios", arch)
+            ..opts("ios", arch, TargetAbi::Normal)
         },
     }
 }
diff --git a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs
index afa92ba..c03a097 100644
--- a/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/i386_apple_ios.rs
@@ -1,10 +1,11 @@
-use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch};
+use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch, TargetAbi};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
+    let arch = Arch::I386;
     // i386-apple-ios is a simulator target, even though it isn't declared
     // that way in the target name like the other ones...
-    let arch = Arch::I386_sim;
+    let abi = TargetAbi::Simulator;
     Target {
         // Clang automatically chooses a more specific target based on
         // IPHONEOS_DEPLOYMENT_TARGET.
@@ -22,6 +23,6 @@
             i128:128-f64:32:64-f80:128-n8:16:32-S128"
             .into(),
         arch: arch.target_arch(),
-        options: TargetOptions { max_atomic_width: Some(64), ..opts("ios", arch) },
+        options: TargetOptions { max_atomic_width: Some(64), ..opts("ios", arch, abi) },
     }
 }
diff --git a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs
index 34a447a..aea6a1a 100644
--- a/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/i686_apple_darwin.rs
@@ -1,10 +1,10 @@
-use crate::spec::base::apple::{macos_llvm_target, opts, Arch};
+use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi};
 use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, TargetOptions};
 
 pub fn target() -> Target {
     // ld64 only understands i386 and not i686
     let arch = Arch::I386;
-    let mut base = opts("macos", arch);
+    let mut base = opts("macos", arch, TargetAbi::Normal);
     base.max_atomic_width = Some(64);
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m32"]);
     base.frame_pointer = FramePointer::Always;
diff --git a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
index 5ff3f07..1259969 100644
--- a/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
+++ b/compiler/rustc_target/src/spec/targets/wasm32_wasip2.rs
@@ -18,7 +18,7 @@
 
 use crate::spec::crt_objects;
 use crate::spec::LinkSelfContainedDefault;
-use crate::spec::{base, Target};
+use crate::spec::{base, RelocModel, Target};
 
 pub fn target() -> Target {
     let mut options = base::wasm::options();
@@ -54,8 +54,13 @@
     // signatures.
     options.entry_name = "__main_void".into();
 
+    // Default to PIC unlike base wasm. This makes precompiled objects such as
+    // the standard library more suitable to be used with shared libaries a la
+    // emscripten's dynamic linking convention.
+    options.relocation_model = RelocModel::Pic;
+
     Target {
-        llvm_target: "wasm32-unknown-unknown".into(),
+        llvm_target: "wasm32-wasip2".into(),
         metadata: crate::spec::TargetMetadata {
             description: None,
             tier: None,
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs
index 1716c59..21acd75 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_darwin.rs
@@ -1,10 +1,10 @@
-use crate::spec::base::apple::{macos_llvm_target, opts, Arch};
+use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi};
 use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let arch = Arch::X86_64;
-    let mut base = opts("macos", arch);
+    let mut base = opts("macos", arch, TargetAbi::Normal);
     base.max_atomic_width = Some(128); // penryn+ supports cmpxchg16b
     base.frame_pointer = FramePointer::Always;
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]);
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs
index fa22c29..ec61b79 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios.rs
@@ -1,11 +1,11 @@
-use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch};
+use crate::spec::base::apple::{ios_sim_llvm_target, opts, Arch, TargetAbi};
 use crate::spec::{SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
+    let arch = Arch::X86_64;
     // x86_64-apple-ios is a simulator target, even though it isn't declared
     // that way in the target name like the other ones...
-    let arch = Arch::X86_64_sim;
-    let mut base = opts("ios", arch);
+    let mut base = opts("ios", arch, TargetAbi::Simulator);
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::THREAD;
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs
index 9b479de..bd967ee 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_ios_macabi.rs
@@ -1,9 +1,9 @@
-use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch};
+use crate::spec::base::apple::{mac_catalyst_llvm_target, opts, Arch, TargetAbi};
 use crate::spec::{SanitizerSet, Target, TargetOptions};
 
 pub fn target() -> Target {
-    let arch = Arch::X86_64_macabi;
-    let mut base = opts("ios", arch);
+    let arch = Arch::X86_64;
+    let mut base = opts("ios", arch, TargetAbi::MacCatalyst);
     base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::LEAK | SanitizerSet::THREAD;
 
     Target {
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs
index f62d31c..55b2e1a 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_tvos.rs
@@ -1,10 +1,11 @@
-use crate::spec::base::apple::{opts, tvos_sim_llvm_target, Arch};
+use crate::spec::base::apple::{opts, tvos_sim_llvm_target, Arch, TargetAbi};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
+    let arch = Arch::X86_64;
     // x86_64-apple-tvos is a simulator target, even though it isn't declared
     // that way in the target name like the other ones...
-    let arch = Arch::X86_64_sim;
+    let abi = TargetAbi::Simulator;
     Target {
         llvm_target: tvos_sim_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
@@ -17,6 +18,6 @@
         data_layout:
             "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
         arch: arch.target_arch(),
-        options: TargetOptions { max_atomic_width: Some(128), ..opts("tvos", arch) },
+        options: TargetOptions { max_atomic_width: Some(128), ..opts("tvos", arch, abi) },
     }
 }
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs
index 371aab8..a783eff 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_apple_watchos_sim.rs
@@ -1,8 +1,8 @@
-use crate::spec::base::apple::{opts, watchos_sim_llvm_target, Arch};
+use crate::spec::base::apple::{opts, watchos_sim_llvm_target, Arch, TargetAbi};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
-    let arch = Arch::X86_64_sim;
+    let arch = Arch::X86_64;
     Target {
         llvm_target: watchos_sim_llvm_target(arch).into(),
         metadata: crate::spec::TargetMetadata {
@@ -15,6 +15,9 @@
         data_layout:
             "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
         arch: arch.target_arch(),
-        options: TargetOptions { max_atomic_width: Some(128), ..opts("watchos", arch) },
+        options: TargetOptions {
+            max_atomic_width: Some(128),
+            ..opts("watchos", arch, TargetAbi::Simulator)
+        },
     }
 }
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
index 11fb28a..bd12d4d 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_gnu.rs
@@ -18,6 +18,13 @@
         | SanitizerSet::THREAD;
     base.supports_xray = true;
 
+    // When we're asked to use the `rust-lld` linker by default, set the appropriate lld-using
+    // linker flavor, and self-contained linker component.
+    if option_env!("CFG_USE_SELF_CONTAINED_LINKER").is_some() {
+        base.linker_flavor = LinkerFlavor::Gnu(Cc::Yes, Lld::Yes);
+        base.link_self_contained = crate::spec::LinkSelfContainedDefault::with_linker();
+    }
+
     Target {
         llvm_target: "x86_64-unknown-linux-gnu".into(),
         metadata: crate::spec::TargetMetadata {
diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs
new file mode 100644
index 0000000..b6e331b
--- /dev/null
+++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_linux_none.rs
@@ -0,0 +1,25 @@
+use crate::spec::{base, Cc, LinkerFlavor, Lld, StackProbeType, Target};
+
+pub fn target() -> Target {
+    let mut base = base::linux::opts();
+    base.cpu = "x86-64".into();
+    base.max_atomic_width = Some(64);
+    base.stack_probes = StackProbeType::Inline;
+    base.linker_flavor = LinkerFlavor::Gnu(Cc::No, Lld::Yes);
+    base.linker = Some("rust-lld".into());
+
+    Target {
+        llvm_target: "x86_64-unknown-linux-none".into(),
+        metadata: crate::spec::TargetMetadata {
+            description: None,
+            tier: None,
+            host_tools: None,
+            std: None,
+        },
+        pointer_width: 64,
+        data_layout:
+            "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(),
+        arch: "x86_64".into(),
+        options: base,
+    }
+}
diff --git a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs
index b17e21e..fe6cbca 100644
--- a/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/targets/x86_64h_apple_darwin.rs
@@ -1,10 +1,10 @@
-use crate::spec::base::apple::{macos_llvm_target, opts, Arch};
+use crate::spec::base::apple::{macos_llvm_target, opts, Arch, TargetAbi};
 use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, SanitizerSet};
 use crate::spec::{Target, TargetOptions};
 
 pub fn target() -> Target {
     let arch = Arch::X86_64h;
-    let mut base = opts("macos", arch);
+    let mut base = opts("macos", arch, TargetAbi::Normal);
     base.max_atomic_width = Some(128);
     base.frame_pointer = FramePointer::Always;
     base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]);
diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml
index 811eb4c..1f4fb57 100644
--- a/compiler/rustc_trait_selection/Cargo.toml
+++ b/compiler/rustc_trait_selection/Cargo.toml
@@ -6,6 +6,7 @@
 [dependencies]
 # tidy-alphabetical-start
 bitflags = "2.4.1"
+derivative = "2.2.0"
 itertools = "0.12"
 rustc_ast = { path = "../rustc_ast" }
 rustc_ast_ir = { path = "../rustc_ast_ir" }
@@ -21,10 +22,13 @@
 rustc_next_trait_solver = { path = "../rustc_next_trait_solver" }
 rustc_parse_format = { path = "../rustc_parse_format" }
 rustc_query_system = { path = "../rustc_query_system" }
+rustc_serialize = { path = "../rustc_serialize" }
 rustc_session = { path = "../rustc_session" }
 rustc_span = { path = "../rustc_span" }
 rustc_target = { path = "../rustc_target" }
 rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] }
+rustc_type_ir = { path = "../rustc_type_ir" }
+rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
 smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
 tracing = "0.1"
 # tidy-alphabetical-end
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 7228a9b..b442446 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -4,7 +4,7 @@
     SubdiagMessageOp, Subdiagnostic,
 };
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_middle::ty::{self, ClosureKind, PolyTraitRef, Ty};
+use rustc_middle::ty::{self, print::PrintTraitRefExt as _, ClosureKind, PolyTraitRef, Ty};
 use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 3dc5550..fc85229 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -10,7 +10,7 @@
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
-use rustc_middle::ty::{GenericArg, ToPredicate};
+use rustc_middle::ty::{GenericArg, Upcast};
 use rustc_span::DUMMY_SP;
 
 use std::fmt::Debug;
@@ -63,7 +63,7 @@
             cause: traits::ObligationCause::dummy(),
             param_env,
             recursion_depth: 0,
-            predicate: ty::Binder::dummy(trait_ref).to_predicate(self.tcx),
+            predicate: trait_ref.upcast(self.tcx),
         };
         self.evaluate_obligation(&obligation).unwrap_or(traits::EvaluationResult::EvaluatedToErr)
     }
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index f1f03b8..521e4ef 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -30,8 +30,6 @@
 
 #[macro_use]
 extern crate tracing;
-#[macro_use]
-extern crate rustc_middle;
 
 pub mod errors;
 pub mod infer;
diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
index f2c441dc..43e61de 100644
--- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs
+++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs
@@ -16,11 +16,12 @@
 //! relate them structurally.
 
 use super::EvalCtxt;
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
 use rustc_middle::ty;
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
-    #[instrument(level = "debug", skip(self), ret)]
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
+    #[instrument(level = "trace", skip(self), ret)]
     pub(super) fn compute_alias_relate_goal(
         &mut self,
         goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>,
@@ -29,7 +30,7 @@
         let Goal { param_env, predicate: (lhs, rhs, direction) } = goal;
 
         // Structurally normalize the lhs.
-        let lhs = if let Some(alias) = lhs.to_alias_ty(self.tcx()) {
+        let lhs = if let Some(alias) = lhs.to_alias_term() {
             let term = self.next_term_infer_of_kind(lhs);
             self.add_normalizes_to_goal(goal.with(tcx, ty::NormalizesTo { alias, term }));
             term
@@ -38,7 +39,7 @@
         };
 
         // Structurally normalize the rhs.
-        let rhs = if let Some(alias) = rhs.to_alias_ty(self.tcx()) {
+        let rhs = if let Some(alias) = rhs.to_alias_term() {
             let term = self.next_term_infer_of_kind(rhs);
             self.add_normalizes_to_goal(goal.with(tcx, ty::NormalizesTo { alias, term }));
             term
@@ -50,13 +51,13 @@
         self.try_evaluate_added_goals()?;
         let lhs = self.resolve_vars_if_possible(lhs);
         let rhs = self.resolve_vars_if_possible(rhs);
-        debug!(?lhs, ?rhs);
+        trace!(?lhs, ?rhs);
 
         let variance = match direction {
             ty::AliasRelationDirection::Equate => ty::Variance::Invariant,
             ty::AliasRelationDirection::Subtype => ty::Variance::Covariant,
         };
-        match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
+        match (lhs.to_alias_term(), rhs.to_alias_term()) {
             (None, None) => {
                 self.relate(param_env, lhs, variance, rhs)?;
                 self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index f2ca42a..1152441 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -1,9 +1,9 @@
 //! Code shared by trait and projection goals for candidate assembly.
 
-use crate::solve::GoalSource;
-use crate::solve::{inspect, EvalCtxt, SolverMode};
 use rustc_hir::def_id::DefId;
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
+use rustc_middle::bug;
 use rustc_middle::traits::solve::inspect::ProbeKind;
 use rustc_middle::traits::solve::{
     CandidateSource, CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult,
@@ -12,10 +12,12 @@
 use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{fast_reject, TypeFoldable};
-use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
+use rustc_middle::ty::{TypeVisitableExt, Upcast};
 use rustc_span::{ErrorGuaranteed, DUMMY_SP};
 use std::fmt::Debug;
-use std::mem;
+
+use crate::solve::GoalSource;
+use crate::solve::{EvalCtxt, SolverMode};
 
 pub(super) mod structural_traits;
 
@@ -25,7 +27,7 @@
 /// and the `result` when using the given `source`.
 #[derive(Debug, Clone)]
 pub(super) struct Candidate<'tcx> {
-    pub(super) source: CandidateSource,
+    pub(super) source: CandidateSource<'tcx>,
     pub(super) result: CanonicalResponse<'tcx>,
 }
 
@@ -46,19 +48,19 @@
     /// work, then produce a response (typically by executing
     /// [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
     fn probe_and_match_goal_against_assumption(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
-        source: CandidateSource,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
+        source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
-        then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
+        then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// Consider a clause, which consists of a "assumption" and some "requirements",
     /// to satisfy a goal. If the requirements hold, then attempt to satisfy our
     /// goal by equating it with the assumption.
     fn probe_and_consider_implied_clause(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
-        parent_source: CandidateSource,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
+        parent_source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
         requirements: impl IntoIterator<Item = (GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>,
@@ -75,8 +77,8 @@
     /// additionally checking all of the supertraits and object bounds to hold,
     /// since they're not implied by the well-formedness of the object type.
     fn probe_and_consider_object_bound_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
-        source: CandidateSource,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
+        source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -99,7 +101,7 @@
     }
 
     fn consider_impl_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
         impl_def_id: DefId,
     ) -> Result<Candidate<'tcx>, NoSolution>;
@@ -111,7 +113,7 @@
     /// Trait goals always hold while projection goals never do. This is a bit arbitrary
     /// but prevents incorrect normalization while hiding any trait errors.
     fn consider_error_guaranteed_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         guar: ErrorGuaranteed,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -120,13 +122,13 @@
     /// These components are given by built-in rules from
     /// [`structural_traits::instantiate_constituent_tys_for_auto_trait`].
     fn consider_auto_trait_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// A trait alias holds if the RHS traits and `where` clauses hold.
     fn consider_trait_alias_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -135,7 +137,7 @@
     /// These components are given by built-in rules from
     /// [`structural_traits::instantiate_constituent_tys_for_sized_trait`].
     fn consider_builtin_sized_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -144,27 +146,27 @@
     /// These components are given by built-in rules from
     /// [`structural_traits::instantiate_constituent_tys_for_copy_clone_trait`].
     fn consider_builtin_copy_clone_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// A type is `PointerLike` if we can compute its layout, and that layout
     /// matches the layout of `usize`.
     fn consider_builtin_pointer_like_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// A type is a `FnPtr` if it is of `FnPtr` type.
     fn consider_builtin_fn_ptr_trait_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// A callable type (a closure, fn def, or fn ptr) is known to implement the `Fn<A>`
     /// family of traits where `A` is given by the signature of the type.
     fn consider_builtin_fn_trait_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
         kind: ty::ClosureKind,
     ) -> Result<Candidate<'tcx>, NoSolution>;
@@ -172,7 +174,7 @@
     /// An async closure is known to implement the `AsyncFn<A>` family of traits
     /// where `A` is given by the signature of the type.
     fn consider_builtin_async_fn_trait_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
         kind: ty::ClosureKind,
     ) -> Result<Candidate<'tcx>, NoSolution>;
@@ -181,13 +183,13 @@
     /// is used internally to delay computation for async closures until after
     /// upvar analysis is performed in HIR typeck.
     fn consider_builtin_async_fn_kind_helper_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// `Tuple` is implemented if the `Self` type is a tuple.
     fn consider_builtin_tuple_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -197,7 +199,7 @@
     /// the built-in types. For structs, the metadata type is given by the struct
     /// tail.
     fn consider_builtin_pointee_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -205,7 +207,7 @@
     /// `Future<Output = O>`, where `O` is given by the coroutine's return type
     /// that was computed during type-checking.
     fn consider_builtin_future_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -213,19 +215,19 @@
     /// `Iterator<Item = O>`, where `O` is given by the generator's yield type
     /// that was computed during type-checking.
     fn consider_builtin_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     /// A coroutine (that comes from a `gen` desugaring) is known to implement
     /// `FusedIterator`
     fn consider_builtin_fused_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     fn consider_builtin_async_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -233,27 +235,27 @@
     /// implement `Coroutine<R, Yield = Y, Return = O>`, given the resume, yield,
     /// and return types of the coroutine computed during type-checking.
     fn consider_builtin_coroutine_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     fn consider_builtin_discriminant_kind_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     fn consider_builtin_async_destruct_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     fn consider_builtin_destruct_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
     fn consider_builtin_transmute_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution>;
 
@@ -265,12 +267,12 @@
     /// otherwise recompute this for codegen. This is a bit of a mess but the
     /// easiest way to maintain the existing behavior for now.
     fn consider_structural_builtin_unsize_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Vec<Candidate<'tcx>>;
 }
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     pub(super) fn assemble_and_evaluate_candidates<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,
@@ -286,7 +288,7 @@
             return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect();
         }
 
-        let goal =
+        let goal: Goal<'tcx, G> =
             goal.with(self.tcx(), goal.predicate.with_self_ty(self.tcx(), normalized_self_ty));
         // Vars that show up in the rest of the goal substs may have been constrained by
         // normalizing the self type as well, since type variables are not uniquified.
@@ -331,7 +333,7 @@
             .enter(|this| this.evaluate_added_goals_and_make_canonical_response(certainty))
     }
 
-    #[instrument(level = "debug", skip_all)]
+    #[instrument(level = "trace", skip_all)]
     fn assemble_non_blanket_impl_candidates<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,
@@ -447,7 +449,7 @@
         }
     }
 
-    #[instrument(level = "debug", skip_all)]
+    #[instrument(level = "trace", skip_all)]
     fn assemble_blanket_impl_candidates<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,
@@ -470,7 +472,7 @@
         }
     }
 
-    #[instrument(level = "debug", skip_all)]
+    #[instrument(level = "trace", skip_all)]
     fn assemble_builtin_impl_candidates<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,
@@ -544,7 +546,7 @@
         }
     }
 
-    #[instrument(level = "debug", skip_all)]
+    #[instrument(level = "trace", skip_all)]
     fn assemble_param_env_candidates<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,
@@ -561,7 +563,7 @@
         }
     }
 
-    #[instrument(level = "debug", skip_all)]
+    #[instrument(level = "trace", skip_all)]
     fn assemble_alias_bound_candidates<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,
@@ -665,7 +667,7 @@
         }
     }
 
-    #[instrument(level = "debug", skip_all)]
+    #[instrument(level = "trace", skip_all)]
     fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,
@@ -744,7 +746,7 @@
                     ecx,
                     CandidateSource::BuiltinImpl(BuiltinImplSource::Object { vtable_base }),
                     goal,
-                    assumption.to_predicate(tcx),
+                    assumption.upcast(tcx),
                 ));
             });
         }
@@ -756,7 +758,7 @@
     ///
     /// To do so we add an ambiguous candidate in case such an unknown impl could
     /// apply to the current goal.
-    #[instrument(level = "debug", skip_all)]
+    #[instrument(level = "trace", skip_all)]
     fn assemble_coherence_unknowable_candidates<G: GoalKind<'tcx>>(
         &mut self,
         goal: Goal<'tcx, G>,
@@ -791,17 +793,16 @@
         goal: Goal<'tcx, G>,
         candidates: &mut Vec<Candidate<'tcx>>,
     ) {
-        // HACK: We temporarily remove the `ProofTreeBuilder` to
-        // avoid adding `Trait` candidates to the candidates used
-        // to prove the current goal.
-        let inspect = mem::replace(&mut self.inspect, inspect::ProofTreeBuilder::new_noop());
-
         let tcx = self.tcx();
         let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> =
             goal.with(tcx, goal.predicate.trait_ref(tcx));
-        let mut trait_candidates_from_env = Vec::new();
-        self.assemble_param_env_candidates(trait_goal, &mut trait_candidates_from_env);
-        self.assemble_alias_bound_candidates(trait_goal, &mut trait_candidates_from_env);
+
+        let mut trait_candidates_from_env = vec![];
+        self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| {
+            ecx.assemble_param_env_candidates(trait_goal, &mut trait_candidates_from_env);
+            ecx.assemble_alias_bound_candidates(trait_goal, &mut trait_candidates_from_env);
+        });
+
         if !trait_candidates_from_env.is_empty() {
             let trait_env_result = self.merge_candidates(trait_candidates_from_env);
             match trait_env_result.unwrap().value.certainty {
@@ -830,7 +831,6 @@
                 }
             }
         }
-        self.inspect = inspect;
     }
 
     /// If there are multiple ways to prove a trait or projection goal, we have
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index a8b1a18..930ae5a 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -3,12 +3,12 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::LangItem;
 use rustc_hir::{def_id::DefId, Movability, Mutability};
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_macros::{TypeFoldable, TypeVisitable};
+use rustc_middle::bug;
 use rustc_middle::traits::solve::Goal;
-use rustc_middle::ty::{
-    self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, Upcast};
 use rustc_span::sym;
 
 use crate::solve::EvalCtxt;
@@ -17,9 +17,9 @@
 //
 // For types with an "existential" binder, i.e. coroutine witnesses, we also
 // instantiate the binder with placeholders eagerly.
-#[instrument(level = "debug", skip(ecx), ret)]
+#[instrument(level = "trace", skip(ecx), ret)]
 pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
-    ecx: &EvalCtxt<'_, 'tcx>,
+    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
     ty: Ty<'tcx>,
 ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
     let tcx = ecx.tcx();
@@ -96,9 +96,9 @@
     }
 }
 
-#[instrument(level = "debug", skip(ecx), ret)]
+#[instrument(level = "trace", skip(ecx), ret)]
 pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
-    ecx: &EvalCtxt<'_, 'tcx>,
+    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
     ty: Ty<'tcx>,
 ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
     match *ty.kind() {
@@ -160,9 +160,9 @@
     }
 }
 
-#[instrument(level = "debug", skip(ecx), ret)]
+#[instrument(level = "trace", skip(ecx), ret)]
 pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
-    ecx: &EvalCtxt<'_, 'tcx>,
+    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
     ty: Ty<'tcx>,
 ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> {
     match *ty.kind() {
@@ -428,7 +428,7 @@
                         tcx.require_lang_item(LangItem::AsyncFnKindHelper, None),
                         [kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
                     )
-                    .to_predicate(tcx),
+                    .upcast(tcx),
                 );
 
                 coroutine_closure_to_ambiguous_coroutine(
@@ -455,7 +455,7 @@
             let nested = vec![
                 bound_sig
                     .rebind(ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()]))
-                    .to_predicate(tcx),
+                    .upcast(tcx),
             ];
             let future_output_def_id = tcx
                 .associated_items(future_trait_def_id)
@@ -483,7 +483,7 @@
             let mut nested = vec![
                 bound_sig
                     .rebind(ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()]))
-                    .to_predicate(tcx),
+                    .upcast(tcx),
             ];
 
             // Additionally, we need to check that the closure kind
@@ -509,7 +509,7 @@
                         async_fn_kind_trait_def_id,
                         [kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
                     )
-                    .to_predicate(tcx),
+                    .upcast(tcx),
                 );
             }
 
@@ -664,7 +664,7 @@
 // normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9
 // for more details.
 pub(in crate::solve) fn predicates_for_object_candidate<'tcx>(
-    ecx: &EvalCtxt<'_, 'tcx>,
+    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
     param_env: ty::ParamEnv<'tcx>,
     trait_ref: ty::TraitRef<'tcx>,
     object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
@@ -698,7 +698,7 @@
                 old_ty,
                 None,
                 "{} has two generic parameters: {} and {}",
-                proj.projection_ty,
+                proj.projection_term,
                 proj.term,
                 old_ty.unwrap()
             );
@@ -717,7 +717,7 @@
 }
 
 struct ReplaceProjectionWith<'a, 'tcx> {
-    ecx: &'a EvalCtxt<'a, 'tcx>,
+    ecx: &'a EvalCtxt<'a, InferCtxt<'tcx>>,
     param_env: ty::ParamEnv<'tcx>,
     mapping: FxHashMap<DefId, ty::PolyProjectionPredicate<'tcx>>,
     nested: Vec<Goal<'tcx, ty::Predicate<'tcx>>>,
@@ -739,7 +739,11 @@
             // FIXME: Technically this equate could be fallible...
             self.nested.extend(
                 self.ecx
-                    .eq_and_get_goals(self.param_env, alias_ty, proj.projection_ty)
+                    .eq_and_get_goals(
+                        self.param_env,
+                        alias_ty,
+                        proj.projection_term.expect_ty(self.ecx.tcx()),
+                    )
                     .expect("expected to be able to unify goal projection with dyn's projection"),
             );
             proj.term.ty().unwrap()
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index 5f73432..9590a82 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -18,13 +18,11 @@
 use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
 use rustc_infer::infer::canonical::CanonicalVarValues;
 use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
-use rustc_infer::infer::resolve::EagerResolver;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::RegionVariableOrigin;
 use rustc_infer::infer::{InferCtxt, InferOk};
 use rustc_infer::traits::solve::NestedNormalizationGoals;
+use rustc_middle::bug;
 use rustc_middle::infer::canonical::Canonical;
-use rustc_middle::infer::unify_key::ConstVariableOrigin;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{
     ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
@@ -32,6 +30,7 @@
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable};
 use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer};
+use rustc_next_trait_solver::resolve::EagerResolver;
 use rustc_span::{Span, DUMMY_SP};
 use std::assert_matches::assert_matches;
 use std::iter;
@@ -41,19 +40,19 @@
     fn var_values(&self) -> CanonicalVarValues<'tcx>;
 }
 
-impl<'tcx> ResponseT<'tcx> for Response<'tcx> {
+impl<'tcx> ResponseT<'tcx> for Response<TyCtxt<'tcx>> {
     fn var_values(&self) -> CanonicalVarValues<'tcx> {
         self.var_values
     }
 }
 
-impl<'tcx, T> ResponseT<'tcx> for inspect::State<'tcx, T> {
+impl<'tcx, T> ResponseT<'tcx> for inspect::State<TyCtxt<'tcx>, T> {
     fn var_values(&self) -> CanonicalVarValues<'tcx> {
         self.var_values
     }
 }
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     /// Canonicalizes the goal remembering the original values
     /// for each bound variable.
     pub(super) fn canonicalize_goal<T: TypeFoldable<TyCtxt<'tcx>>>(
@@ -85,7 +84,7 @@
     ///   the values inferred while solving the instantiated goal.
     /// - `external_constraints`: additional constraints which aren't expressible
     ///   using simple unification of inference variables.
-    #[instrument(level = "debug", skip(self), ret)]
+    #[instrument(level = "trace", skip(self), ret)]
     pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response(
         &mut self,
         certainty: Certainty,
@@ -168,7 +167,7 @@
     /// external constraints do not need to record that opaque, since if it is
     /// further constrained by inference, that will be passed back in the var
     /// values.
-    #[instrument(level = "debug", skip(self), ret)]
+    #[instrument(level = "trace", skip(self), ret)]
     fn compute_external_query_constraints(
         &self,
         normalization_nested_goals: NestedNormalizationGoals<'tcx>,
@@ -176,7 +175,7 @@
         // We only check for leaks from universes which were entered inside
         // of the query.
         self.infcx.leak_check(self.max_input_universe, None).map_err(|e| {
-            debug!(?e, "failed the leak check");
+            trace!(?e, "failed the leak check");
             NoSolution
         })?;
 
@@ -336,7 +335,7 @@
     /// whether an alias is rigid by using the trait solver. When instantiating a response
     /// from the solver we assume that the solver correctly handled aliases and therefore
     /// always relate them structurally here.
-    #[instrument(level = "debug", skip(infcx))]
+    #[instrument(level = "trace", skip(infcx))]
     fn unify_query_var_values(
         infcx: &InferCtxt<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
@@ -385,7 +384,7 @@
     var_values: &[ty::GenericArg<'tcx>],
     max_input_universe: ty::UniverseIndex,
     data: T,
-) -> inspect::CanonicalState<'tcx, T> {
+) -> inspect::CanonicalState<TyCtxt<'tcx>, T> {
     let var_values = CanonicalVarValues { var_values: infcx.tcx.mk_args(var_values) };
     let state = inspect::State { var_values, data };
     let state = state.fold_with(&mut EagerResolver::new(infcx));
@@ -409,12 +408,13 @@
 /// This currently assumes that unifying the var values trivially succeeds.
 /// Adding any inference constraints which weren't present when originally
 /// computing the canonical query can result in bugs.
+#[instrument(level = "trace", skip(infcx, span, param_env))]
 pub(in crate::solve) fn instantiate_canonical_state<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>(
     infcx: &InferCtxt<'tcx>,
     span: Span,
     param_env: ty::ParamEnv<'tcx>,
     orig_values: &mut Vec<ty::GenericArg<'tcx>>,
-    state: inspect::CanonicalState<'tcx, T>,
+    state: inspect::CanonicalState<TyCtxt<'tcx>, T>,
 ) -> T {
     // In case any fresh inference variables have been created between `state`
     // and the previous instantiation, extend `orig_values` for it.
@@ -424,12 +424,8 @@
             ty::GenericArgKind::Lifetime(_) => {
                 infcx.next_region_var(RegionVariableOrigin::MiscVariable(span)).into()
             }
-            ty::GenericArgKind::Type(_) => {
-                infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span }).into()
-            }
-            ty::GenericArgKind::Const(ct) => infcx
-                .next_const_var(ct.ty(), ConstVariableOrigin { param_def_id: None, span })
-                .into(),
+            ty::GenericArgKind::Type(_) => infcx.next_ty_var(span).into(),
+            ty::GenericArgKind::Const(ct) => infcx.next_const_var(ct.ty(), span).into(),
         };
 
         orig_values.push(unconstrained);
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
index 98aac58..7e1d7d7 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs
@@ -1,21 +1,19 @@
+use std::io::Write;
+use std::ops::ControlFlow;
+
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::at::ToTrace;
-use rustc_infer::infer::canonical::CanonicalVarValues;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::{
     BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt,
 };
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals};
 use rustc_infer::traits::ObligationCause;
-use rustc_macros::{extension, HashStable};
-use rustc_middle::infer::canonical::CanonicalVarInfos;
-use rustc_middle::infer::unify_key::ConstVariableOrigin;
-use rustc_middle::traits::solve::inspect;
+use rustc_macros::{extension, HashStable, HashStable_NoContext, TyDecodable, TyEncodable};
+use rustc_middle::bug;
 use rustc_middle::traits::solve::{
-    CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaques, PredefinedOpaquesData,
-    QueryResult,
+    inspect, CanonicalInput, CanonicalResponse, Certainty, PredefinedOpaquesData, QueryResult,
 };
 use rustc_middle::traits::specialization_graph;
 use rustc_middle::ty::{
@@ -24,8 +22,8 @@
 };
 use rustc_session::config::DumpSolverProofTree;
 use rustc_span::DUMMY_SP;
-use std::io::Write;
-use std::ops::ControlFlow;
+use rustc_type_ir::{self as ir, CanonicalVarValues, Interner};
+use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 
 use crate::traits::coherence;
 use crate::traits::vtable::{count_own_vtable_entries, prepare_vtable_segments, VtblSegment};
@@ -40,7 +38,11 @@
 mod probe;
 mod select;
 
-pub struct EvalCtxt<'a, 'tcx> {
+pub struct EvalCtxt<
+    'a,
+    Infcx: InferCtxtLike<Interner = I>,
+    I: Interner = <Infcx as InferCtxtLike>::Interner,
+> {
     /// The inference context that backs (mostly) inference and placeholder terms
     /// instantiated while solving goals.
     ///
@@ -56,11 +58,11 @@
     /// If some `InferCtxt` method is missing, please first think defensively about
     /// the method's compatibility with this solver, or if an existing one does
     /// the job already.
-    infcx: &'a InferCtxt<'tcx>,
+    infcx: &'a Infcx,
 
     /// The variable info for the `var_values`, only used to make an ambiguous response
     /// with no constraints.
-    variables: CanonicalVarInfos<'tcx>,
+    variables: I::CanonicalVars,
     /// Whether we're currently computing a `NormalizesTo` goal. Unlike other goals,
     /// `NormalizesTo` goals act like functions with the expected term always being
     /// fully unconstrained. This would weaken inference however, as the nested goals
@@ -69,9 +71,9 @@
     /// when then adds these to its own context. The caller is always an `AliasRelate`
     /// goal so this never leaks out of the solver.
     is_normalizes_to_goal: bool,
-    pub(super) var_values: CanonicalVarValues<'tcx>,
+    pub(super) var_values: CanonicalVarValues<I>,
 
-    predefined_opaques_in_body: PredefinedOpaques<'tcx>,
+    predefined_opaques_in_body: I::PredefinedOpaques,
 
     /// The highest universe index nameable by the caller.
     ///
@@ -84,9 +86,9 @@
     /// new placeholders to the caller.
     pub(super) max_input_universe: ty::UniverseIndex,
 
-    pub(super) search_graph: &'a mut SearchGraph<'tcx>,
+    pub(super) search_graph: &'a mut SearchGraph<I>,
 
-    nested_goals: NestedGoals<'tcx>,
+    nested_goals: NestedGoals<I>,
 
     // Has this `EvalCtxt` errored out with `NoSolution` in `try_evaluate_added_goals`?
     //
@@ -96,11 +98,15 @@
     // evaluation code.
     tainted: Result<(), NoSolution>,
 
-    pub(super) inspect: ProofTreeBuilder<'tcx>,
+    pub(super) inspect: ProofTreeBuilder<I>,
 }
 
-#[derive(Default, Debug, Clone)]
-pub(super) struct NestedGoals<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(Clone(bound = ""), Debug(bound = ""), Default(bound = ""))]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[derive(TyDecodable, TyEncodable, HashStable_NoContext)]
+// FIXME: This can be made crate-private once `EvalCtxt` also lives in this crate.
+pub struct NestedGoals<I: Interner> {
     /// These normalizes-to goals are treated specially during the evaluation
     /// loop. In each iteration we take the RHS of the projection, replace it with
     /// a fresh inference variable, and only after evaluating that goal do we
@@ -111,17 +117,17 @@
     ///
     /// Forgetting to replace the RHS with a fresh inference variable when we evaluate
     /// this goal results in an ICE..
-    pub(super) normalizes_to_goals: Vec<Goal<'tcx, ty::NormalizesTo<'tcx>>>,
+    pub normalizes_to_goals: Vec<ir::solve::Goal<I, ir::NormalizesTo<I>>>,
     /// The rest of the goals which have not yet processed or remain ambiguous.
-    pub(super) goals: Vec<(GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>,
+    pub goals: Vec<(GoalSource, ir::solve::Goal<I, I::Predicate>)>,
 }
 
-impl<'tcx> NestedGoals<'tcx> {
-    pub(super) fn new() -> Self {
+impl<I: Interner> NestedGoals<I> {
+    pub fn new() -> Self {
         Self { normalizes_to_goals: Vec::new(), goals: Vec::new() }
     }
 
-    pub(super) fn is_empty(&self) -> bool {
+    pub fn is_empty(&self) -> bool {
         self.normalizes_to_goals.is_empty() && self.goals.is_empty()
     }
 }
@@ -144,14 +150,15 @@
         &self,
         goal: Goal<'tcx, ty::Predicate<'tcx>>,
         generate_proof_tree: GenerateProofTree,
-    ) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<'tcx>>) {
+    ) -> (Result<(bool, Certainty), NoSolution>, Option<inspect::GoalEvaluation<TyCtxt<'tcx>>>)
+    {
         EvalCtxt::enter_root(self, generate_proof_tree, |ecx| {
             ecx.evaluate_goal(GoalEvaluationKind::Root, GoalSource::Misc, goal)
         })
     }
 }
 
-impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
+impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
     pub(super) fn solver_mode(&self) -> SolverMode {
         self.search_graph.solver_mode()
     }
@@ -166,8 +173,8 @@
     pub(super) fn enter_root<R>(
         infcx: &InferCtxt<'tcx>,
         generate_proof_tree: GenerateProofTree,
-        f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> R,
-    ) -> (R, Option<inspect::GoalEvaluation<'tcx>>) {
+        f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> R,
+    ) -> (R, Option<inspect::GoalEvaluation<TyCtxt<'tcx>>>) {
         let mode = if infcx.intercrate { SolverMode::Coherence } else { SolverMode::Normal };
         let mut search_graph = search_graph::SearchGraph::new(mode);
 
@@ -219,10 +226,10 @@
     /// and registering opaques from the canonicalized input.
     fn enter_canonical<R>(
         tcx: TyCtxt<'tcx>,
-        search_graph: &'a mut search_graph::SearchGraph<'tcx>,
+        search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>,
         canonical_input: CanonicalInput<'tcx>,
-        canonical_goal_evaluation: &mut ProofTreeBuilder<'tcx>,
-        f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>, Goal<'tcx, ty::Predicate<'tcx>>) -> R,
+        canonical_goal_evaluation: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+        f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>, Goal<'tcx, ty::Predicate<'tcx>>) -> R,
     ) -> R {
         let intercrate = match search_graph.solver_mode() {
             SolverMode::Normal => false,
@@ -281,9 +288,9 @@
     #[instrument(level = "debug", skip(tcx, search_graph, goal_evaluation), ret)]
     fn evaluate_canonical_goal(
         tcx: TyCtxt<'tcx>,
-        search_graph: &'a mut search_graph::SearchGraph<'tcx>,
+        search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>,
         canonical_input: CanonicalInput<'tcx>,
-        goal_evaluation: &mut ProofTreeBuilder<'tcx>,
+        goal_evaluation: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
     ) -> QueryResult<'tcx> {
         let mut canonical_goal_evaluation =
             goal_evaluation.new_canonical_goal_evaluation(canonical_input);
@@ -460,7 +467,7 @@
         }
     }
 
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "trace", skip(self))]
     pub(super) fn add_normalizes_to_goal(&mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) {
         self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal);
         self.nested_goals.normalizes_to_goals.push(goal);
@@ -474,7 +481,7 @@
 
     // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning
     // the certainty of all the goals.
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "trace", skip(self))]
     pub(super) fn try_evaluate_added_goals(&mut self) -> Result<Certainty, NoSolution> {
         self.inspect.start_evaluate_added_goals();
         let mut response = Ok(Certainty::overflow(false));
@@ -528,7 +535,7 @@
                 unconstrained_goal,
             )?;
             // Add the nested goals from normalization to our own nested goals.
-            debug!(?nested_goals);
+            trace!(?nested_goals);
             goals.goals.extend(nested_goals);
 
             // Finally, equate the goal's RHS with the unconstrained var.
@@ -594,21 +601,19 @@
     }
 }
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     pub(super) fn tcx(&self) -> TyCtxt<'tcx> {
         self.infcx.tcx
     }
 
     pub(super) fn next_ty_infer(&mut self) -> Ty<'tcx> {
-        let ty = self.infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span: DUMMY_SP });
+        let ty = self.infcx.next_ty_var(DUMMY_SP);
         self.inspect.add_var_value(ty);
         ty
     }
 
     pub(super) fn next_const_infer(&mut self, ty: Ty<'tcx>) -> ty::Const<'tcx> {
-        let ct = self
-            .infcx
-            .next_const_var(ty, ConstVariableOrigin { param_def_id: None, span: DUMMY_SP });
+        let ct = self.infcx.next_const_var(ty, DUMMY_SP);
         self.inspect.add_var_value(ct);
         ct
     }
@@ -626,7 +631,7 @@
     ///
     /// This is the case if the `term` does not occur in any other part of the predicate
     /// and is able to name all other placeholder and inference variables.
-    #[instrument(level = "debug", skip(self), ret)]
+    #[instrument(level = "trace", skip(self), ret)]
     pub(super) fn term_is_fully_unconstrained(
         &self,
         goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
@@ -722,7 +727,7 @@
             && goal.param_env.visit_with(&mut visitor).is_continue()
     }
 
-    #[instrument(level = "debug", skip(self, param_env), ret)]
+    #[instrument(level = "trace", skip(self, param_env), ret)]
     pub(super) fn eq<T: ToTrace<'tcx>>(
         &mut self,
         param_env: ty::ParamEnv<'tcx>,
@@ -737,7 +742,7 @@
                 self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
             })
             .map_err(|e| {
-                debug!(?e, "failed to equate");
+                trace!(?e, "failed to equate");
                 NoSolution
             })
     }
@@ -747,11 +752,11 @@
     /// Normally we emit a nested `AliasRelate` when equating an inference
     /// variable and an alias. This causes us to instead constrain the inference
     /// variable to the alias without emitting a nested alias relate goals.
-    #[instrument(level = "debug", skip(self, param_env), ret)]
+    #[instrument(level = "trace", skip(self, param_env), ret)]
     pub(super) fn relate_rigid_alias_non_alias(
         &mut self,
         param_env: ty::ParamEnv<'tcx>,
-        alias: ty::AliasTy<'tcx>,
+        alias: ty::AliasTerm<'tcx>,
         variance: ty::Variance,
         term: ty::Term<'tcx>,
     ) -> Result<(), NoSolution> {
@@ -768,13 +773,13 @@
             // Alternatively we could modify `Equate` for this case by adding another
             // variant to `StructurallyRelateAliases`.
             let identity_args = self.fresh_args_for_item(alias.def_id);
-            let rigid_ctor = ty::AliasTy::new(tcx, alias.def_id, identity_args);
-            let ctor_ty = rigid_ctor.to_ty(tcx);
+            let rigid_ctor = ty::AliasTerm::new(tcx, alias.def_id, identity_args);
+            let ctor_term = rigid_ctor.to_term(tcx);
             let InferOk { value: (), obligations } = self
                 .infcx
                 .at(&ObligationCause::dummy(), param_env)
-                .trace(term, ctor_ty.into())
-                .eq_structurally_relating_aliases(term, ctor_ty.into())?;
+                .trace(term, ctor_term)
+                .eq_structurally_relating_aliases(term, ctor_term)?;
             debug_assert!(obligations.is_empty());
             self.relate(param_env, alias, variance, rigid_ctor)
         } else {
@@ -785,7 +790,7 @@
     /// This sohuld only be used when we're either instantiating a previously
     /// unconstrained "return value" or when we're sure that all aliases in
     /// the types are rigid.
-    #[instrument(level = "debug", skip(self, param_env), ret)]
+    #[instrument(level = "trace", skip(self, param_env), ret)]
     pub(super) fn eq_structurally_relating_aliases<T: ToTrace<'tcx>>(
         &mut self,
         param_env: ty::ParamEnv<'tcx>,
@@ -802,7 +807,7 @@
         Ok(())
     }
 
-    #[instrument(level = "debug", skip(self, param_env), ret)]
+    #[instrument(level = "trace", skip(self, param_env), ret)]
     pub(super) fn sub<T: ToTrace<'tcx>>(
         &mut self,
         param_env: ty::ParamEnv<'tcx>,
@@ -817,12 +822,12 @@
                 self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
             })
             .map_err(|e| {
-                debug!(?e, "failed to subtype");
+                trace!(?e, "failed to subtype");
                 NoSolution
             })
     }
 
-    #[instrument(level = "debug", skip(self, param_env), ret)]
+    #[instrument(level = "trace", skip(self, param_env), ret)]
     pub(super) fn relate<T: ToTrace<'tcx>>(
         &mut self,
         param_env: ty::ParamEnv<'tcx>,
@@ -838,7 +843,7 @@
                 self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into()));
             })
             .map_err(|e| {
-                debug!(?e, "failed to relate");
+                trace!(?e, "failed to relate");
                 NoSolution
             })
     }
@@ -863,7 +868,7 @@
                 obligations.into_iter().map(|o| o.into()).collect()
             })
             .map_err(|e| {
-                debug!(?e, "failed to equate");
+                trace!(?e, "failed to equate");
                 NoSolution
             })
     }
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
index ee23f49..1748c9b 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/probe.rs
@@ -1,24 +1,27 @@
 use crate::solve::assembly::Candidate;
 
 use super::EvalCtxt;
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::BuiltinImplSource;
-use rustc_middle::traits::{
-    query::NoSolution,
-    solve::{inspect, CandidateSource, QueryResult},
-};
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::solve::{inspect, CandidateSource, QueryResult};
+use rustc_middle::ty::TyCtxt;
 use std::marker::PhantomData;
 
 pub(in crate::solve) struct ProbeCtxt<'me, 'a, 'tcx, F, T> {
-    ecx: &'me mut EvalCtxt<'a, 'tcx>,
+    ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>,
     probe_kind: F,
     _result: PhantomData<T>,
 }
 
 impl<'tcx, F, T> ProbeCtxt<'_, '_, 'tcx, F, T>
 where
-    F: FnOnce(&T) -> inspect::ProbeKind<'tcx>,
+    F: FnOnce(&T) -> inspect::ProbeKind<TyCtxt<'tcx>>,
 {
-    pub(in crate::solve) fn enter(self, f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> T) -> T {
+    pub(in crate::solve) fn enter(
+        self,
+        f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> T,
+    ) -> T {
         let ProbeCtxt { ecx: outer_ecx, probe_kind, _result } = self;
 
         let infcx = outer_ecx.infcx;
@@ -51,27 +54,28 @@
 
 pub(in crate::solve) struct TraitProbeCtxt<'me, 'a, 'tcx, F> {
     cx: ProbeCtxt<'me, 'a, 'tcx, F, QueryResult<'tcx>>,
-    source: CandidateSource,
+    source: CandidateSource<'tcx>,
 }
 
 impl<'tcx, F> TraitProbeCtxt<'_, '_, 'tcx, F>
 where
-    F: FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>,
+    F: FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<TyCtxt<'tcx>>,
 {
+    #[instrument(level = "debug", skip_all, fields(source = ?self.source))]
     pub(in crate::solve) fn enter(
         self,
-        f: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
+        f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         self.cx.enter(|ecx| f(ecx)).map(|result| Candidate { source: self.source, result })
     }
 }
 
-impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
+impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
     /// `probe_kind` is only called when proof tree building is enabled so it can be
     /// as expensive as necessary to output the desired information.
     pub(in crate::solve) fn probe<F, T>(&mut self, probe_kind: F) -> ProbeCtxt<'_, 'a, 'tcx, F, T>
     where
-        F: FnOnce(&T) -> inspect::ProbeKind<'tcx>,
+        F: FnOnce(&T) -> inspect::ProbeKind<TyCtxt<'tcx>>,
     {
         ProbeCtxt { ecx: self, probe_kind, _result: PhantomData }
     }
@@ -79,16 +83,24 @@
     pub(in crate::solve) fn probe_builtin_trait_candidate(
         &mut self,
         source: BuiltinImplSource,
-    ) -> TraitProbeCtxt<'_, 'a, 'tcx, impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>>
-    {
+    ) -> TraitProbeCtxt<
+        '_,
+        'a,
+        'tcx,
+        impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<TyCtxt<'tcx>>,
+    > {
         self.probe_trait_candidate(CandidateSource::BuiltinImpl(source))
     }
 
     pub(in crate::solve) fn probe_trait_candidate(
         &mut self,
-        source: CandidateSource,
-    ) -> TraitProbeCtxt<'_, 'a, 'tcx, impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<'tcx>>
-    {
+        source: CandidateSource<'tcx>,
+    ) -> TraitProbeCtxt<
+        '_,
+        'a,
+        'tcx,
+        impl FnOnce(&QueryResult<'tcx>) -> inspect::ProbeKind<TyCtxt<'tcx>>,
+    > {
         TraitProbeCtxt {
             cx: ProbeCtxt {
                 ecx: self,
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
index 7efc951..68c0c8b 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs
@@ -8,6 +8,7 @@
     PolyTraitObligation, Selection, SelectionError, SelectionResult,
 };
 use rustc_macros::extension;
+use rustc_middle::{bug, span_bug};
 use rustc_span::Span;
 
 use crate::solve::inspect::{self, ProofTreeInferCtxtExt};
@@ -175,7 +176,8 @@
         | ProbeKind::UnsizeAssembly
         | ProbeKind::UpcastProjectionCompatibility
         | ProbeKind::OpaqueTypeStorageLookup { result: _ }
-        | ProbeKind::Root { result: _ } => {
+        | ProbeKind::Root { result: _ }
+        | ProbeKind::ShadowedEnvProbing => {
             span_bug!(span, "didn't expect to assemble trait candidate from {:#?}", cand.kind())
         }
     })
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 39d2ec4..7291eb0 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -3,18 +3,18 @@
 
 use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
-use rustc_infer::traits::solve::inspect::ProbeKind;
 use rustc_infer::traits::solve::{CandidateSource, GoalSource, MaybeCause};
 use rustc_infer::traits::{
     self, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes, Obligation,
-    ObligationCause, PredicateObligation, SelectionError, TraitEngine,
+    ObligationCause, ObligationCauseCode, PredicateObligation, SelectionError, TraitEngine,
 };
+use rustc_middle::bug;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::symbol::sym;
 
 use super::eval_ctxt::GenerateProofTree;
-use super::inspect::{InspectCandidate, InspectGoal, ProofTreeInferCtxtExt, ProofTreeVisitor};
+use super::inspect::{self, ProofTreeInferCtxtExt, ProofTreeVisitor};
 use super::{Certainty, InferCtxtEvalExt};
 
 /// A trait engine using the new trait solver.
@@ -119,7 +119,7 @@
 }
 
 impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
-    #[instrument(level = "debug", skip(self, infcx))]
+    #[instrument(level = "trace", skip(self, infcx))]
     fn register_predicate_obligation(
         &mut self,
         infcx: &InferCtxt<'tcx>,
@@ -203,39 +203,35 @@
 
     let code = match obligation.predicate.kind().skip_binder() {
         ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) => {
-            FulfillmentErrorCode::ProjectionError(
+            FulfillmentErrorCode::Project(
                 // FIXME: This could be a `Sorts` if the term is a type
                 MismatchedProjectionTypes { err: TypeError::Mismatch },
             )
         }
         ty::PredicateKind::NormalizesTo(..) => {
-            FulfillmentErrorCode::ProjectionError(MismatchedProjectionTypes {
-                err: TypeError::Mismatch,
-            })
+            FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch })
         }
         ty::PredicateKind::AliasRelate(_, _, _) => {
-            FulfillmentErrorCode::ProjectionError(MismatchedProjectionTypes {
-                err: TypeError::Mismatch,
-            })
+            FulfillmentErrorCode::Project(MismatchedProjectionTypes { err: TypeError::Mismatch })
         }
         ty::PredicateKind::Subtype(pred) => {
             let (a, b) = infcx.enter_forall_and_leak_universe(
                 obligation.predicate.kind().rebind((pred.a, pred.b)),
             );
             let expected_found = ExpectedFound::new(true, a, b);
-            FulfillmentErrorCode::SubtypeError(expected_found, TypeError::Sorts(expected_found))
+            FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
         }
         ty::PredicateKind::Coerce(pred) => {
             let (a, b) = infcx.enter_forall_and_leak_universe(
                 obligation.predicate.kind().rebind((pred.a, pred.b)),
             );
             let expected_found = ExpectedFound::new(false, a, b);
-            FulfillmentErrorCode::SubtypeError(expected_found, TypeError::Sorts(expected_found))
+            FulfillmentErrorCode::Subtype(expected_found, TypeError::Sorts(expected_found))
         }
         ty::PredicateKind::Clause(_)
         | ty::PredicateKind::ObjectSafe(_)
         | ty::PredicateKind::Ambiguous => {
-            FulfillmentErrorCode::SelectionError(SelectionError::Unimplemented)
+            FulfillmentErrorCode::Select(SelectionError::Unimplemented)
         }
         ty::PredicateKind::ConstEquate(..) => {
             bug!("unexpected goal: {obligation:?}")
@@ -247,16 +243,23 @@
 
 fn fulfillment_error_for_stalled<'tcx>(
     infcx: &InferCtxt<'tcx>,
-    obligation: PredicateObligation<'tcx>,
+    root_obligation: PredicateObligation<'tcx>,
 ) -> FulfillmentError<'tcx> {
-    let code = infcx.probe(|_| {
-        match infcx.evaluate_root_goal(obligation.clone().into(), GenerateProofTree::Never).0 {
+    let (code, refine_obligation) = infcx.probe(|_| {
+        match infcx.evaluate_root_goal(root_obligation.clone().into(), GenerateProofTree::Never).0 {
             Ok((_, Certainty::Maybe(MaybeCause::Ambiguity))) => {
-                FulfillmentErrorCode::Ambiguity { overflow: None }
+                (FulfillmentErrorCode::Ambiguity { overflow: None }, true)
             }
-            Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => {
-                FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) }
-            }
+            Ok((_, Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit }))) => (
+                FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) },
+                // Don't look into overflows because we treat overflows weirdly anyways.
+                // In `instantiate_response_discarding_overflow` we set `has_changed = false`,
+                // recomputing the goal again during `find_best_leaf_obligation` may apply
+                // inference guidance that makes other goals go from ambig -> pass, for example.
+                //
+                // FIXME: We should probably just look into overflows here.
+                false,
+            ),
             Ok((_, Certainty::Yes)) => {
                 bug!("did not expect successful goal when collecting ambiguity errors")
             }
@@ -267,9 +270,13 @@
     });
 
     FulfillmentError {
-        obligation: find_best_leaf_obligation(infcx, &obligation, true),
+        obligation: if refine_obligation {
+            find_best_leaf_obligation(infcx, &root_obligation, true)
+        } else {
+            root_obligation.clone()
+        },
         code,
-        root_obligation: obligation,
+        root_obligation,
     }
 }
 
@@ -305,41 +312,50 @@
         res
     }
 
-    /// Filter out the candidates that aren't either error or ambiguous (depending
-    /// on what we are looking for), and also throw out candidates that have no
-    /// failing WC (or higher-ranked obligations, for which there should only be
-    /// one candidate anyways -- but I digress). This most likely means that the
-    /// goal just didn't unify at all, e.g. a param candidate with an alias in it.
+    /// Filter out the candidates that aren't interesting to visit for the
+    /// purposes of reporting errors. For ambiguities, we only consider
+    /// candidates that may hold. For errors, we only consider candidates that
+    /// *don't* hold and which have impl-where clauses that also don't hold.
     fn non_trivial_candidates<'a>(
         &self,
-        goal: &'a InspectGoal<'a, 'tcx>,
-    ) -> Vec<InspectCandidate<'a, 'tcx>> {
-        let mut candidates = goal
-            .candidates()
-            .into_iter()
-            .filter(|candidate| match self.consider_ambiguities {
-                true => matches!(candidate.result(), Ok(Certainty::Maybe(_))),
-                false => matches!(candidate.result(), Err(_)),
-            })
-            .collect::<Vec<_>>();
-
-        // If we have >1 candidate, one may still be due to "boring" reasons, like
-        // an alias-relate that failed to hold when deeply evaluated. We really
-        // don't care about reasons like this.
-        if candidates.len() > 1 {
-            candidates.retain(|candidate| {
-                goal.infcx().probe(|_| {
-                    candidate.instantiate_nested_goals(self.span()).iter().any(|nested_goal| {
-                        matches!(
-                            nested_goal.source(),
-                            GoalSource::ImplWhereBound | GoalSource::InstantiateHigherRanked
-                        ) && match self.consider_ambiguities {
-                            true => matches!(nested_goal.result(), Ok(Certainty::Maybe(_))),
-                            false => matches!(nested_goal.result(), Err(_)),
-                        }
-                    })
-                })
-            });
+        goal: &'a inspect::InspectGoal<'a, 'tcx>,
+    ) -> Vec<inspect::InspectCandidate<'a, 'tcx>> {
+        let mut candidates = goal.candidates();
+        match self.consider_ambiguities {
+            true => {
+                // If we have an ambiguous obligation, we must consider *all* candidates
+                // that hold, or else we may guide inference causing other goals to go
+                // from ambig -> pass/fail.
+                candidates.retain(|candidate| candidate.result().is_ok());
+            }
+            false => {
+                // If we have >1 candidate, one may still be due to "boring" reasons, like
+                // an alias-relate that failed to hold when deeply evaluated. We really
+                // don't care about reasons like this.
+                if candidates.len() > 1 {
+                    candidates.retain(|candidate| {
+                        goal.infcx().probe(|_| {
+                            candidate.instantiate_nested_goals(self.span()).iter().any(
+                                |nested_goal| {
+                                    matches!(
+                                        nested_goal.source(),
+                                        GoalSource::ImplWhereBound
+                                            | GoalSource::InstantiateHigherRanked
+                                    ) && match self.consider_ambiguities {
+                                        true => {
+                                            matches!(
+                                                nested_goal.result(),
+                                                Ok(Certainty::Maybe(MaybeCause::Ambiguity))
+                                            )
+                                        }
+                                        false => matches!(nested_goal.result(), Err(_)),
+                                    }
+                                },
+                            )
+                        })
+                    });
+                }
+            }
         }
 
         candidates
@@ -353,58 +369,91 @@
         self.obligation.cause.span
     }
 
-    fn visit_goal(&mut self, goal: &super::inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
+    fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
         let candidates = self.non_trivial_candidates(goal);
         let [candidate] = candidates.as_slice() else {
             return ControlFlow::Break(self.obligation.clone());
         };
 
         // Don't walk into impls that have `do_not_recommend`.
-        if let ProbeKind::TraitCandidate { source: CandidateSource::Impl(impl_def_id), result: _ } =
-            candidate.kind()
-            && goal.infcx().tcx.has_attr(impl_def_id, sym::do_not_recommend)
+        if let inspect::ProbeKind::TraitCandidate {
+            source: CandidateSource::Impl(impl_def_id),
+            result: _,
+        } = candidate.kind()
+            && goal
+                .infcx()
+                .tcx
+                .has_attrs_with_path(impl_def_id, &[sym::diagnostic, sym::do_not_recommend])
         {
             return ControlFlow::Break(self.obligation.clone());
         }
 
-        // FIXME: Could we extract a trait ref from a projection here too?
+        let tcx = goal.infcx().tcx;
         // FIXME: Also, what about considering >1 layer up the stack? May be necessary
         // for normalizes-to.
-        let Some(parent_trait_pred) = goal.goal().predicate.to_opt_poly_trait_pred() else {
-            return ControlFlow::Break(self.obligation.clone());
+        let pred_kind = goal.goal().predicate.kind();
+        let child_mode = match pred_kind.skip_binder() {
+            ty::PredicateKind::Clause(ty::ClauseKind::Trait(parent_trait_pred)) => {
+                ChildMode::Trait(pred_kind.rebind(parent_trait_pred))
+            }
+            ty::PredicateKind::NormalizesTo(normalizes_to)
+                if matches!(
+                    normalizes_to.alias.kind(tcx),
+                    ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst
+                ) =>
+            {
+                ChildMode::Trait(pred_kind.rebind(ty::TraitPredicate {
+                    trait_ref: normalizes_to.alias.trait_ref(tcx),
+                    polarity: ty::PredicatePolarity::Positive,
+                }))
+            }
+            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => {
+                ChildMode::WellFormedObligation
+            }
+            _ => {
+                return ControlFlow::Break(self.obligation.clone());
+            }
         };
 
-        let tcx = goal.infcx().tcx;
         let mut impl_where_bound_count = 0;
         for nested_goal in candidate.instantiate_nested_goals(self.span()) {
+            let make_obligation = |cause| Obligation {
+                cause,
+                param_env: nested_goal.goal().param_env,
+                predicate: nested_goal.goal().predicate,
+                recursion_depth: self.obligation.recursion_depth + 1,
+            };
+
             let obligation;
-            match nested_goal.source() {
-                GoalSource::Misc => {
+            match (child_mode, nested_goal.source()) {
+                (ChildMode::Trait(_), GoalSource::Misc) => {
                     continue;
                 }
-                GoalSource::ImplWhereBound => {
-                    obligation = Obligation {
-                        cause: derive_cause(
-                            tcx,
-                            candidate.kind(),
-                            self.obligation.cause.clone(),
-                            impl_where_bound_count,
-                            parent_trait_pred,
-                        ),
-                        param_env: nested_goal.goal().param_env,
-                        predicate: nested_goal.goal().predicate,
-                        recursion_depth: self.obligation.recursion_depth + 1,
-                    };
+                (ChildMode::Trait(parent_trait_pred), GoalSource::ImplWhereBound) => {
+                    obligation = make_obligation(derive_cause(
+                        tcx,
+                        candidate.kind(),
+                        self.obligation.cause.clone(),
+                        impl_where_bound_count,
+                        parent_trait_pred,
+                    ));
                     impl_where_bound_count += 1;
                 }
-                GoalSource::InstantiateHigherRanked => {
+                // Skip over a higher-ranked predicate.
+                (_, GoalSource::InstantiateHigherRanked) => {
                     obligation = self.obligation.clone();
                 }
+                (ChildMode::WellFormedObligation, _) => {
+                    obligation = make_obligation(self.obligation.cause.clone());
+                }
             }
 
             // Skip nested goals that aren't the *reason* for our goal's failure.
             match self.consider_ambiguities {
-                true if matches!(nested_goal.result(), Ok(Certainty::Maybe(_))) => {}
+                true if matches!(
+                    nested_goal.result(),
+                    Ok(Certainty::Maybe(MaybeCause::Ambiguity))
+                ) => {}
                 false if matches!(nested_goal.result(), Err(_)) => {}
                 _ => continue,
             }
@@ -416,20 +465,35 @@
     }
 }
 
+#[derive(Copy, Clone)]
+enum ChildMode<'tcx> {
+    // Try to derive an `ObligationCause::{ImplDerived,BuiltinDerived}`,
+    // and skip all `GoalSource::Misc`, which represent useless obligations
+    // such as alias-eq which may not hold.
+    Trait(ty::PolyTraitPredicate<'tcx>),
+    // Skip trying to derive an `ObligationCause` from this obligation, and
+    // report *all* sub-obligations as if they came directly from the parent
+    // obligation.
+    WellFormedObligation,
+}
+
 fn derive_cause<'tcx>(
     tcx: TyCtxt<'tcx>,
-    candidate_kind: ProbeKind<'tcx>,
+    candidate_kind: inspect::ProbeKind<TyCtxt<'tcx>>,
     mut cause: ObligationCause<'tcx>,
     idx: usize,
     parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
 ) -> ObligationCause<'tcx> {
     match candidate_kind {
-        ProbeKind::TraitCandidate { source: CandidateSource::Impl(impl_def_id), result: _ } => {
+        inspect::ProbeKind::TraitCandidate {
+            source: CandidateSource::Impl(impl_def_id),
+            result: _,
+        } => {
             if let Some((_, span)) =
                 tcx.predicates_of(impl_def_id).instantiate_identity(tcx).iter().nth(idx)
             {
                 cause = cause.derived_cause(parent_trait_pred, |derived| {
-                    traits::ImplDerivedObligation(Box::new(traits::ImplDerivedObligationCause {
+                    ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause {
                         derived,
                         impl_or_alias_def_id: impl_def_id,
                         impl_def_predicate_index: Some(idx),
@@ -438,8 +502,11 @@
                 })
             }
         }
-        ProbeKind::TraitCandidate { source: CandidateSource::BuiltinImpl(..), result: _ } => {
-            cause = cause.derived_cause(parent_trait_pred, traits::BuiltinDerivedObligation);
+        inspect::ProbeKind::TraitCandidate {
+            source: CandidateSource::BuiltinImpl(..),
+            result: _,
+        } => {
+            cause = cause.derived_cause(parent_trait_pred, ObligationCauseCode::BuiltinDerived);
         }
         _ => {}
     };
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index fa4323a..737d03f 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -11,17 +11,15 @@
 
 use rustc_ast_ir::try_visit;
 use rustc_ast_ir::visit::VisitorResult;
-use rustc_infer::infer::resolve::EagerResolver;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
 use rustc_macros::extension;
-use rustc_middle::infer::unify_key::ConstVariableOrigin;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{inspect, QueryResult};
 use rustc_middle::traits::solve::{Certainty, Goal};
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty;
-use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::{TyCtxt, TypeFoldable};
+use rustc_middle::{bug, ty};
+use rustc_next_trait_solver::resolve::EagerResolver;
 use rustc_span::{Span, DUMMY_SP};
 
 use crate::solve::eval_ctxt::canonical;
@@ -39,7 +37,7 @@
     orig_values: Vec<ty::GenericArg<'tcx>>,
     goal: Goal<'tcx, ty::Predicate<'tcx>>,
     result: Result<Certainty, NoSolution>,
-    evaluation_kind: inspect::CanonicalGoalEvaluationKind<'tcx>,
+    evaluation_kind: inspect::CanonicalGoalEvaluationKind<TyCtxt<'tcx>>,
     normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>,
     source: GoalSource,
 }
@@ -90,16 +88,17 @@
 
 pub struct InspectCandidate<'a, 'tcx> {
     goal: &'a InspectGoal<'a, 'tcx>,
-    kind: inspect::ProbeKind<'tcx>,
-    nested_goals: Vec<(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>)>,
-    final_state: inspect::CanonicalState<'tcx, ()>,
-    impl_args: Option<inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>>>,
+    kind: inspect::ProbeKind<TyCtxt<'tcx>>,
+    nested_goals:
+        Vec<(GoalSource, inspect::CanonicalState<TyCtxt<'tcx>, Goal<'tcx, ty::Predicate<'tcx>>>)>,
+    final_state: inspect::CanonicalState<TyCtxt<'tcx>, ()>,
+    impl_args: Option<inspect::CanonicalState<TyCtxt<'tcx>, ty::GenericArgsRef<'tcx>>>,
     result: QueryResult<'tcx>,
     shallow_certainty: Certainty,
 }
 
 impl<'a, 'tcx> InspectCandidate<'a, 'tcx> {
-    pub fn kind(&self) -> inspect::ProbeKind<'tcx> {
+    pub fn kind(&self) -> inspect::ProbeKind<TyCtxt<'tcx>> {
         self.kind
     }
 
@@ -146,6 +145,11 @@
     /// inference constraints, and optionally the args of an impl if this candidate
     /// came from a `CandidateSource::Impl`. This function modifies the state of the
     /// `infcx`.
+    #[instrument(
+        level = "debug",
+        skip_all,
+        fields(goal = ?self.goal.goal, nested_goals = ?self.nested_goals)
+    )]
     pub fn instantiate_nested_goals_and_opt_impl_args(
         &self,
         span: Span,
@@ -201,22 +205,28 @@
             .map(|(source, goal)| match goal.predicate.kind().no_bound_vars() {
                 Some(ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })) => {
                     let unconstrained_term = match term.unpack() {
-                        ty::TermKind::Ty(_) => infcx
-                            .next_ty_var(TypeVariableOrigin { param_def_id: None, span })
-                            .into(),
-                        ty::TermKind::Const(ct) => infcx
-                            .next_const_var(
-                                ct.ty(),
-                                ConstVariableOrigin { param_def_id: None, span },
-                            )
-                            .into(),
+                        ty::TermKind::Ty(_) => infcx.next_ty_var(span).into(),
+                        ty::TermKind::Const(ct) => infcx.next_const_var(ct.ty(), span).into(),
                     };
                     let goal =
                         goal.with(infcx.tcx, ty::NormalizesTo { alias, term: unconstrained_term });
-                    let proof_tree = EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| {
-                        ecx.evaluate_goal_raw(GoalEvaluationKind::Root, GoalSource::Misc, goal)
-                    })
-                    .1;
+                    // We have to use a `probe` here as evaluating a `NormalizesTo` can constrain the
+                    // expected term. This means that candidates which only fail due to nested goals
+                    // and which normalize to a different term then the final result could ICE: when
+                    // building their proof tree, the expected term was unconstrained, but when
+                    // instantiating the candidate it is already constrained to the result of another
+                    // candidate.
+                    let proof_tree = infcx
+                        .probe(|_| {
+                            EvalCtxt::enter_root(infcx, GenerateProofTree::Yes, |ecx| {
+                                ecx.evaluate_goal_raw(
+                                    GoalEvaluationKind::Root,
+                                    GoalSource::Misc,
+                                    goal,
+                                )
+                            })
+                        })
+                        .1;
                     InspectGoal::new(
                         infcx,
                         self.goal.depth + 1,
@@ -225,13 +235,17 @@
                         source,
                     )
                 }
-                _ => InspectGoal::new(
-                    infcx,
-                    self.goal.depth + 1,
-                    infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1.unwrap(),
-                    None,
-                    source,
-                ),
+                _ => {
+                    // We're using a probe here as evaluating a goal could constrain
+                    // inference variables by choosing one candidate. If we then recurse
+                    // into another candidate who ends up with different inference
+                    // constraints, we get an ICE if we already applied the constraints
+                    // from the chosen candidate.
+                    let proof_tree = infcx
+                        .probe(|_| infcx.evaluate_root_goal(goal, GenerateProofTree::Yes).1)
+                        .unwrap();
+                    InspectGoal::new(infcx, self.goal.depth + 1, proof_tree, None, source)
+                }
             })
             .collect();
 
@@ -267,9 +281,9 @@
         candidates: &mut Vec<InspectCandidate<'a, 'tcx>>,
         nested_goals: &mut Vec<(
             GoalSource,
-            inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>,
+            inspect::CanonicalState<TyCtxt<'tcx>, Goal<'tcx, ty::Predicate<'tcx>>>,
         )>,
-        probe: &inspect::Probe<'tcx>,
+        probe: &inspect::Probe<TyCtxt<'tcx>>,
     ) {
         let mut shallow_certainty = None;
         let mut impl_args = None;
@@ -277,12 +291,25 @@
             match *step {
                 inspect::ProbeStep::AddGoal(source, goal) => nested_goals.push((source, goal)),
                 inspect::ProbeStep::NestedProbe(ref probe) => {
-                    // Nested probes have to prove goals added in their parent
-                    // but do not leak them, so we truncate the added goals
-                    // afterwards.
-                    let num_goals = nested_goals.len();
-                    self.candidates_recur(candidates, nested_goals, probe);
-                    nested_goals.truncate(num_goals);
+                    match probe.kind {
+                        // These never assemble candidates for the goal we're trying to solve.
+                        inspect::ProbeKind::UpcastProjectionCompatibility
+                        | inspect::ProbeKind::ShadowedEnvProbing => continue,
+
+                        inspect::ProbeKind::NormalizedSelfTyAssembly
+                        | inspect::ProbeKind::UnsizeAssembly
+                        | inspect::ProbeKind::Root { .. }
+                        | inspect::ProbeKind::TryNormalizeNonRigid { .. }
+                        | inspect::ProbeKind::TraitCandidate { .. }
+                        | inspect::ProbeKind::OpaqueTypeStorageLookup { .. } => {
+                            // Nested probes have to prove goals added in their parent
+                            // but do not leak them, so we truncate the added goals
+                            // afterwards.
+                            let num_goals = nested_goals.len();
+                            self.candidates_recur(candidates, nested_goals, probe);
+                            nested_goals.truncate(num_goals);
+                        }
+                    }
                 }
                 inspect::ProbeStep::MakeCanonicalResponse { shallow_certainty: c } => {
                     assert_eq!(shallow_certainty.replace(c), None);
@@ -295,9 +322,10 @@
         }
 
         match probe.kind {
-            inspect::ProbeKind::NormalizedSelfTyAssembly
-            | inspect::ProbeKind::UnsizeAssembly
-            | inspect::ProbeKind::UpcastProjectionCompatibility => (),
+            inspect::ProbeKind::UpcastProjectionCompatibility
+            | inspect::ProbeKind::ShadowedEnvProbing => bug!(),
+
+            inspect::ProbeKind::NormalizedSelfTyAssembly | inspect::ProbeKind::UnsizeAssembly => {}
 
             // We add a candidate even for the root evaluation if there
             // is only one way to prove a given goal, e.g. for `WellFormed`.
@@ -360,7 +388,7 @@
     fn new(
         infcx: &'a InferCtxt<'tcx>,
         depth: usize,
-        root: inspect::GoalEvaluation<'tcx>,
+        root: inspect::GoalEvaluation<TyCtxt<'tcx>>,
         normalizes_to_term_hack: Option<NormalizesToTermHack<'tcx>>,
         source: GoalSource,
     ) -> Self {
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
index 3c55050..803300c 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs
@@ -6,13 +6,15 @@
 use std::mem;
 
 use rustc_infer::infer::InferCtxt;
+use rustc_middle::bug;
 use rustc_middle::infer::canonical::CanonicalVarValues;
 use rustc_middle::traits::query::NoSolution;
-use rustc_middle::traits::solve::{
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_next_trait_solver::solve::{
     CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult,
 };
-use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::config::DumpSolverProofTree;
+use rustc_type_ir::Interner;
 
 use crate::solve::eval_ctxt::canonical;
 use crate::solve::{self, inspect, GenerateProofTree};
@@ -37,49 +39,51 @@
 /// trees. At the end of trait solving `ProofTreeBuilder::finalize`
 /// is called to recursively convert the whole structure to a
 /// finished proof tree.
-pub(in crate::solve) struct ProofTreeBuilder<'tcx> {
-    state: Option<Box<DebugSolver<'tcx>>>,
+pub(in crate::solve) struct ProofTreeBuilder<I: Interner> {
+    state: Option<Box<DebugSolver<I>>>,
 }
 
 /// The current state of the proof tree builder, at most places
 /// in the code, only one or two variants are actually possible.
 ///
 /// We simply ICE in case that assumption is broken.
-#[derive(Debug)]
-enum DebugSolver<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(Debug(bound = ""))]
+enum DebugSolver<I: Interner> {
     Root,
-    GoalEvaluation(WipGoalEvaluation<'tcx>),
-    CanonicalGoalEvaluation(WipCanonicalGoalEvaluation<'tcx>),
-    GoalEvaluationStep(WipGoalEvaluationStep<'tcx>),
+    GoalEvaluation(WipGoalEvaluation<I>),
+    CanonicalGoalEvaluation(WipCanonicalGoalEvaluation<I>),
+    GoalEvaluationStep(WipGoalEvaluationStep<I>),
 }
 
-impl<'tcx> From<WipGoalEvaluation<'tcx>> for DebugSolver<'tcx> {
-    fn from(g: WipGoalEvaluation<'tcx>) -> DebugSolver<'tcx> {
+impl<I: Interner> From<WipGoalEvaluation<I>> for DebugSolver<I> {
+    fn from(g: WipGoalEvaluation<I>) -> DebugSolver<I> {
         DebugSolver::GoalEvaluation(g)
     }
 }
 
-impl<'tcx> From<WipCanonicalGoalEvaluation<'tcx>> for DebugSolver<'tcx> {
-    fn from(g: WipCanonicalGoalEvaluation<'tcx>) -> DebugSolver<'tcx> {
+impl<I: Interner> From<WipCanonicalGoalEvaluation<I>> for DebugSolver<I> {
+    fn from(g: WipCanonicalGoalEvaluation<I>) -> DebugSolver<I> {
         DebugSolver::CanonicalGoalEvaluation(g)
     }
 }
 
-impl<'tcx> From<WipGoalEvaluationStep<'tcx>> for DebugSolver<'tcx> {
-    fn from(g: WipGoalEvaluationStep<'tcx>) -> DebugSolver<'tcx> {
+impl<I: Interner> From<WipGoalEvaluationStep<I>> for DebugSolver<I> {
+    fn from(g: WipGoalEvaluationStep<I>) -> DebugSolver<I> {
         DebugSolver::GoalEvaluationStep(g)
     }
 }
 
-#[derive(Eq, PartialEq, Debug)]
-struct WipGoalEvaluation<'tcx> {
-    pub uncanonicalized_goal: Goal<'tcx, ty::Predicate<'tcx>>,
-    pub kind: WipGoalEvaluationKind<'tcx>,
-    pub evaluation: Option<WipCanonicalGoalEvaluation<'tcx>>,
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+struct WipGoalEvaluation<I: Interner> {
+    pub uncanonicalized_goal: Goal<I, I::Predicate>,
+    pub kind: WipGoalEvaluationKind<I>,
+    pub evaluation: Option<WipCanonicalGoalEvaluation<I>>,
 }
 
-impl<'tcx> WipGoalEvaluation<'tcx> {
-    fn finalize(self) -> inspect::GoalEvaluation<'tcx> {
+impl<I: Interner> WipGoalEvaluation<I> {
+    fn finalize(self) -> inspect::GoalEvaluation<I> {
         inspect::GoalEvaluation {
             uncanonicalized_goal: self.uncanonicalized_goal,
             kind: match self.kind {
@@ -93,21 +97,23 @@
     }
 }
 
-#[derive(Eq, PartialEq, Debug)]
-pub(in crate::solve) enum WipGoalEvaluationKind<'tcx> {
-    Root { orig_values: Vec<ty::GenericArg<'tcx>> },
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+pub(in crate::solve) enum WipGoalEvaluationKind<I: Interner> {
+    Root { orig_values: Vec<I::GenericArg> },
     Nested,
 }
 
-#[derive(Eq, PartialEq)]
-pub(in crate::solve) enum WipCanonicalGoalEvaluationKind<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""))]
+pub(in crate::solve) enum WipCanonicalGoalEvaluationKind<I: Interner> {
     Overflow,
     CycleInStack,
     ProvisionalCacheHit,
-    Interned { revisions: &'tcx [inspect::GoalEvaluationStep<'tcx>] },
+    Interned { revisions: I::GoalEvaluationSteps },
 }
 
-impl std::fmt::Debug for WipCanonicalGoalEvaluationKind<'_> {
+impl<I: Interner> std::fmt::Debug for WipCanonicalGoalEvaluationKind<I> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
             Self::Overflow => write!(f, "Overflow"),
@@ -118,18 +124,19 @@
     }
 }
 
-#[derive(Eq, PartialEq, Debug)]
-struct WipCanonicalGoalEvaluation<'tcx> {
-    goal: CanonicalInput<'tcx>,
-    kind: Option<WipCanonicalGoalEvaluationKind<'tcx>>,
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+struct WipCanonicalGoalEvaluation<I: Interner> {
+    goal: CanonicalInput<I>,
+    kind: Option<WipCanonicalGoalEvaluationKind<I>>,
     /// Only used for uncached goals. After we finished evaluating
     /// the goal, this is interned and moved into `kind`.
-    revisions: Vec<WipGoalEvaluationStep<'tcx>>,
-    result: Option<QueryResult<'tcx>>,
+    revisions: Vec<WipGoalEvaluationStep<I>>,
+    result: Option<QueryResult<I>>,
 }
 
-impl<'tcx> WipCanonicalGoalEvaluation<'tcx> {
-    fn finalize(self) -> inspect::CanonicalGoalEvaluation<'tcx> {
+impl<I: Interner> WipCanonicalGoalEvaluation<I> {
+    fn finalize(self) -> inspect::CanonicalGoalEvaluation<I> {
         assert!(self.revisions.is_empty());
         let kind = match self.kind.unwrap() {
             WipCanonicalGoalEvaluationKind::Overflow => {
@@ -150,14 +157,15 @@
     }
 }
 
-#[derive(Eq, PartialEq, Debug)]
-struct WipAddedGoalsEvaluation<'tcx> {
-    evaluations: Vec<Vec<WipGoalEvaluation<'tcx>>>,
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+struct WipAddedGoalsEvaluation<I: Interner> {
+    evaluations: Vec<Vec<WipGoalEvaluation<I>>>,
     result: Option<Result<Certainty, NoSolution>>,
 }
 
-impl<'tcx> WipAddedGoalsEvaluation<'tcx> {
-    fn finalize(self) -> inspect::AddedGoalsEvaluation<'tcx> {
+impl<I: Interner> WipAddedGoalsEvaluation<I> {
+    fn finalize(self) -> inspect::AddedGoalsEvaluation<I> {
         inspect::AddedGoalsEvaluation {
             evaluations: self
                 .evaluations
@@ -171,22 +179,23 @@
     }
 }
 
-#[derive(Eq, PartialEq, Debug)]
-struct WipGoalEvaluationStep<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+struct WipGoalEvaluationStep<I: Interner> {
     /// Unlike `EvalCtxt::var_values`, we append a new
     /// generic arg here whenever we create a new inference
     /// variable.
     ///
     /// This is necessary as we otherwise don't unify these
     /// vars when instantiating multiple `CanonicalState`.
-    var_values: Vec<ty::GenericArg<'tcx>>,
-    instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
+    var_values: Vec<I::GenericArg>,
+    instantiated_goal: QueryInput<I, I::Predicate>,
     probe_depth: usize,
-    evaluation: WipProbe<'tcx>,
+    evaluation: WipProbe<I>,
 }
 
-impl<'tcx> WipGoalEvaluationStep<'tcx> {
-    fn current_evaluation_scope(&mut self) -> &mut WipProbe<'tcx> {
+impl<I: Interner> WipGoalEvaluationStep<I> {
+    fn current_evaluation_scope(&mut self) -> &mut WipProbe<I> {
         let mut current = &mut self.evaluation;
         for _ in 0..self.probe_depth {
             match current.steps.last_mut() {
@@ -197,7 +206,7 @@
         current
     }
 
-    fn added_goals_evaluation(&mut self) -> &mut WipAddedGoalsEvaluation<'tcx> {
+    fn added_goals_evaluation(&mut self) -> &mut WipAddedGoalsEvaluation<I> {
         let mut current = &mut self.evaluation;
         loop {
             match current.steps.last_mut() {
@@ -208,7 +217,7 @@
         }
     }
 
-    fn finalize(self) -> inspect::GoalEvaluationStep<'tcx> {
+    fn finalize(self) -> inspect::GoalEvaluationStep<I> {
         let evaluation = self.evaluation.finalize();
         match evaluation.kind {
             inspect::ProbeKind::Root { .. } => (),
@@ -218,16 +227,17 @@
     }
 }
 
-#[derive(Eq, PartialEq, Debug)]
-struct WipProbe<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+struct WipProbe<I: Interner> {
     initial_num_var_values: usize,
-    steps: Vec<WipProbeStep<'tcx>>,
-    kind: Option<inspect::ProbeKind<'tcx>>,
-    final_state: Option<inspect::CanonicalState<'tcx, ()>>,
+    steps: Vec<WipProbeStep<I>>,
+    kind: Option<inspect::ProbeKind<I>>,
+    final_state: Option<inspect::CanonicalState<I, ()>>,
 }
 
-impl<'tcx> WipProbe<'tcx> {
-    fn finalize(self) -> inspect::Probe<'tcx> {
+impl<I: Interner> WipProbe<I> {
+    fn finalize(self) -> inspect::Probe<I> {
         inspect::Probe {
             steps: self.steps.into_iter().map(WipProbeStep::finalize).collect(),
             kind: self.kind.unwrap(),
@@ -236,17 +246,18 @@
     }
 }
 
-#[derive(Eq, PartialEq, Debug)]
-enum WipProbeStep<'tcx> {
-    AddGoal(GoalSource, inspect::CanonicalState<'tcx, Goal<'tcx, ty::Predicate<'tcx>>>),
-    EvaluateGoals(WipAddedGoalsEvaluation<'tcx>),
-    NestedProbe(WipProbe<'tcx>),
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Debug(bound = ""))]
+enum WipProbeStep<I: Interner> {
+    AddGoal(GoalSource, inspect::CanonicalState<I, Goal<I, I::Predicate>>),
+    EvaluateGoals(WipAddedGoalsEvaluation<I>),
+    NestedProbe(WipProbe<I>),
     MakeCanonicalResponse { shallow_certainty: Certainty },
-    RecordImplArgs { impl_args: inspect::CanonicalState<'tcx, ty::GenericArgsRef<'tcx>> },
+    RecordImplArgs { impl_args: inspect::CanonicalState<I, I::GenericArgs> },
 }
 
-impl<'tcx> WipProbeStep<'tcx> {
-    fn finalize(self) -> inspect::ProbeStep<'tcx> {
+impl<I: Interner> WipProbeStep<I> {
+    fn finalize(self) -> inspect::ProbeStep<I> {
         match self {
             WipProbeStep::AddGoal(source, goal) => inspect::ProbeStep::AddGoal(source, goal),
             WipProbeStep::EvaluateGoals(eval) => inspect::ProbeStep::EvaluateGoals(eval.finalize()),
@@ -261,26 +272,27 @@
     }
 }
 
-impl<'tcx> ProofTreeBuilder<'tcx> {
-    fn new(state: impl Into<DebugSolver<'tcx>>) -> ProofTreeBuilder<'tcx> {
+// FIXME: Genericize this impl.
+impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> {
+    fn new(state: impl Into<DebugSolver<TyCtxt<'tcx>>>) -> ProofTreeBuilder<TyCtxt<'tcx>> {
         ProofTreeBuilder { state: Some(Box::new(state.into())) }
     }
 
-    fn nested<T: Into<DebugSolver<'tcx>>>(&self, state: impl FnOnce() -> T) -> Self {
+    fn nested<T: Into<DebugSolver<TyCtxt<'tcx>>>>(&self, state: impl FnOnce() -> T) -> Self {
         ProofTreeBuilder { state: self.state.as_ref().map(|_| Box::new(state().into())) }
     }
 
-    fn as_mut(&mut self) -> Option<&mut DebugSolver<'tcx>> {
+    fn as_mut(&mut self) -> Option<&mut DebugSolver<TyCtxt<'tcx>>> {
         self.state.as_deref_mut()
     }
 
-    pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<'tcx> {
+    pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<TyCtxt<'tcx>> {
         let mut nested = ProofTreeBuilder { state: self.state.take() };
         nested.enter_probe();
         nested
     }
 
-    pub fn finalize(self) -> Option<inspect::GoalEvaluation<'tcx>> {
+    pub fn finalize(self) -> Option<inspect::GoalEvaluation<TyCtxt<'tcx>>> {
         match *self.state? {
             DebugSolver::GoalEvaluation(wip_goal_evaluation) => {
                 Some(wip_goal_evaluation.finalize())
@@ -292,7 +304,7 @@
     pub fn new_maybe_root(
         tcx: TyCtxt<'tcx>,
         generate_proof_tree: GenerateProofTree,
-    ) -> ProofTreeBuilder<'tcx> {
+    ) -> ProofTreeBuilder<TyCtxt<'tcx>> {
         match generate_proof_tree {
             GenerateProofTree::Never => ProofTreeBuilder::new_noop(),
             GenerateProofTree::IfEnabled => {
@@ -310,11 +322,11 @@
         }
     }
 
-    pub fn new_root() -> ProofTreeBuilder<'tcx> {
+    pub fn new_root() -> ProofTreeBuilder<TyCtxt<'tcx>> {
         ProofTreeBuilder::new(DebugSolver::Root)
     }
 
-    pub fn new_noop() -> ProofTreeBuilder<'tcx> {
+    pub fn new_noop() -> ProofTreeBuilder<TyCtxt<'tcx>> {
         ProofTreeBuilder { state: None }
     }
 
@@ -324,10 +336,10 @@
 
     pub(in crate::solve) fn new_goal_evaluation(
         &mut self,
-        goal: Goal<'tcx, ty::Predicate<'tcx>>,
+        goal: Goal<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
         orig_values: &[ty::GenericArg<'tcx>],
         kind: solve::GoalEvaluationKind,
-    ) -> ProofTreeBuilder<'tcx> {
+    ) -> ProofTreeBuilder<TyCtxt<'tcx>> {
         self.nested(|| WipGoalEvaluation {
             uncanonicalized_goal: goal,
             kind: match kind {
@@ -342,8 +354,8 @@
 
     pub fn new_canonical_goal_evaluation(
         &mut self,
-        goal: CanonicalInput<'tcx>,
-    ) -> ProofTreeBuilder<'tcx> {
+        goal: CanonicalInput<TyCtxt<'tcx>>,
+    ) -> ProofTreeBuilder<TyCtxt<'tcx>> {
         self.nested(|| WipCanonicalGoalEvaluation {
             goal,
             kind: None,
@@ -355,7 +367,7 @@
     pub fn finalize_evaluation(
         &mut self,
         tcx: TyCtxt<'tcx>,
-    ) -> Option<&'tcx [inspect::GoalEvaluationStep<'tcx>]> {
+    ) -> Option<&'tcx [inspect::GoalEvaluationStep<TyCtxt<'tcx>>]> {
         self.as_mut().map(|this| match this {
             DebugSolver::CanonicalGoalEvaluation(evaluation) => {
                 let revisions = mem::take(&mut evaluation.revisions)
@@ -370,7 +382,10 @@
         })
     }
 
-    pub fn canonical_goal_evaluation(&mut self, canonical_goal_evaluation: ProofTreeBuilder<'tcx>) {
+    pub fn canonical_goal_evaluation(
+        &mut self,
+        canonical_goal_evaluation: ProofTreeBuilder<TyCtxt<'tcx>>,
+    ) {
         if let Some(this) = self.as_mut() {
             match (this, *canonical_goal_evaluation.state.unwrap()) {
                 (
@@ -385,7 +400,7 @@
         }
     }
 
-    pub fn goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind<'tcx>) {
+    pub fn goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind<TyCtxt<'tcx>>) {
         if let Some(this) = self.as_mut() {
             match this {
                 DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => {
@@ -396,7 +411,7 @@
         }
     }
 
-    pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<'tcx>) {
+    pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<TyCtxt<'tcx>>) {
         if let Some(this) = self.as_mut() {
             match (this, *goal_evaluation.state.unwrap()) {
                 (
@@ -417,8 +432,8 @@
     pub fn new_goal_evaluation_step(
         &mut self,
         var_values: CanonicalVarValues<'tcx>,
-        instantiated_goal: QueryInput<'tcx, ty::Predicate<'tcx>>,
-    ) -> ProofTreeBuilder<'tcx> {
+        instantiated_goal: QueryInput<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
+    ) -> ProofTreeBuilder<TyCtxt<'tcx>> {
         self.nested(|| WipGoalEvaluationStep {
             var_values: var_values.var_values.to_vec(),
             instantiated_goal,
@@ -432,7 +447,7 @@
         })
     }
 
-    pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<'tcx>) {
+    pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<TyCtxt<'tcx>>) {
         if let Some(this) = self.as_mut() {
             match (this, *goal_evaluation_step.state.unwrap()) {
                 (
@@ -473,7 +488,7 @@
         }
     }
 
-    pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind<'tcx>) {
+    pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind<TyCtxt<'tcx>>) {
         match self.as_mut() {
             None => {}
             Some(DebugSolver::GoalEvaluationStep(state)) => {
@@ -509,7 +524,7 @@
         &mut self,
         infcx: &InferCtxt<'tcx>,
         max_input_universe: ty::UniverseIndex,
-        goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
+        goal: Goal<TyCtxt<'tcx>, ty::NormalizesTo<'tcx>>,
     ) {
         self.add_goal(
             infcx,
@@ -524,7 +539,7 @@
         infcx: &InferCtxt<'tcx>,
         max_input_universe: ty::UniverseIndex,
         source: GoalSource,
-        goal: Goal<'tcx, ty::Predicate<'tcx>>,
+        goal: Goal<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
     ) {
         match self.as_mut() {
             None => {}
@@ -578,7 +593,7 @@
         }
     }
 
-    pub fn finish_probe(mut self) -> ProofTreeBuilder<'tcx> {
+    pub fn finish_probe(mut self) -> ProofTreeBuilder<TyCtxt<'tcx>> {
         match self.as_mut() {
             None => {}
             Some(DebugSolver::GoalEvaluationStep(state)) => {
@@ -626,7 +641,7 @@
         }
     }
 
-    pub fn query_result(&mut self, result: QueryResult<'tcx>) {
+    pub fn query_result(&mut self, result: QueryResult<TyCtxt<'tcx>>) {
         if let Some(this) = self.as_mut() {
             match this {
                 DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => {
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index b2b076e..60722d3 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -15,15 +15,17 @@
 //! about it on zulip.
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::canonical::{Canonical, CanonicalVarValues};
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_macros::extension;
+use rustc_middle::bug;
 use rustc_middle::infer::canonical::CanonicalVarInfos;
 use rustc_middle::traits::solve::{
     CanonicalResponse, Certainty, ExternalConstraintsData, Goal, GoalSource, QueryResult, Response,
 };
-use rustc_middle::ty::{self, AliasRelationDirection, Ty, TyCtxt, UniverseIndex};
 use rustc_middle::ty::{
-    CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, TypeOutlivesPredicate,
+    self, AliasRelationDirection, CoercePredicate, RegionOutlivesPredicate, SubtypePredicate, Ty,
+    TyCtxt, TypeOutlivesPredicate, UniverseIndex,
 };
 
 mod alias_relate;
@@ -73,7 +75,7 @@
 }
 
 #[extension(trait CanonicalResponseExt)]
-impl<'tcx> Canonical<'tcx, Response<'tcx>> {
+impl<'tcx> Canonical<'tcx, Response<TyCtxt<'tcx>>> {
     fn has_no_inference_or_external_constraints(&self) -> bool {
         self.value.external_constraints.region_constraints.is_empty()
             && self.value.var_values.is_identity()
@@ -81,8 +83,8 @@
     }
 }
 
-impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
-    #[instrument(level = "debug", skip(self))]
+impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> {
+    #[instrument(level = "trace", skip(self))]
     fn compute_type_outlives_goal(
         &mut self,
         goal: Goal<'tcx, TypeOutlivesPredicate<'tcx>>,
@@ -92,7 +94,7 @@
         self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "trace", skip(self))]
     fn compute_region_outlives_goal(
         &mut self,
         goal: Goal<'tcx, RegionOutlivesPredicate<'tcx>>,
@@ -102,7 +104,7 @@
         self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
     }
 
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "trace", skip(self))]
     fn compute_coerce_goal(
         &mut self,
         goal: Goal<'tcx, CoercePredicate<'tcx>>,
@@ -117,7 +119,7 @@
         })
     }
 
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "trace", skip(self))]
     fn compute_subtype_goal(
         &mut self,
         goal: Goal<'tcx, SubtypePredicate<'tcx>>,
@@ -138,7 +140,7 @@
         }
     }
 
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "trace", skip(self))]
     fn compute_well_formed_goal(
         &mut self,
         goal: Goal<'tcx, ty::GenericArg<'tcx>>,
@@ -152,7 +154,7 @@
         }
     }
 
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "trace", skip(self))]
     fn compute_const_evaluatable_goal(
         &mut self,
         Goal { param_env, predicate: ct }: Goal<'tcx, ty::Const<'tcx>>,
@@ -189,7 +191,7 @@
         }
     }
 
-    #[instrument(level = "debug", skip(self), ret)]
+    #[instrument(level = "trace", skip(self), ret)]
     fn compute_const_arg_has_type_goal(
         &mut self,
         goal: Goal<'tcx, (ty::Const<'tcx>, Ty<'tcx>)>,
@@ -200,8 +202,8 @@
     }
 }
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
-    #[instrument(level = "debug", skip(self, goals))]
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
+    #[instrument(level = "trace", skip(self, goals))]
     fn add_goals(
         &mut self,
         source: GoalSource,
@@ -215,7 +217,7 @@
     /// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`.
     ///
     /// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`.
-    #[instrument(level = "debug", skip(self), ret)]
+    #[instrument(level = "trace", skip(self), ret)]
     fn try_merge_responses(
         &mut self,
         responses: &[CanonicalResponse<'tcx>],
@@ -241,7 +243,7 @@
     }
 
     /// If we fail to merge responses we flounder and return overflow or ambiguity.
-    #[instrument(level = "debug", skip(self), ret)]
+    #[instrument(level = "trace", skip(self), ret)]
     fn flounder(&mut self, responses: &[CanonicalResponse<'tcx>]) -> QueryResult<'tcx> {
         if responses.is_empty() {
             return Err(NoSolution);
@@ -263,7 +265,7 @@
     /// This function is necessary in nearly all cases before matching on a type.
     /// Not doing so is likely to be incomplete and therefore unsound during
     /// coherence.
-    #[instrument(level = "debug", skip(self, param_env), ret)]
+    #[instrument(level = "trace", skip(self, param_env), ret)]
     fn structurally_normalize_ty(
         &mut self,
         param_env: ty::ParamEnv<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/solve/normalize.rs b/compiler/rustc_trait_selection/src/solve/normalize.rs
index 65ef465..5d5161e 100644
--- a/compiler/rustc_trait_selection/src/solve/normalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalize.rs
@@ -3,13 +3,11 @@
 use crate::traits::{BoundVarReplacer, PlaceholderReplacer};
 use rustc_data_structures::stack::ensure_sufficient_stack;
 use rustc_infer::infer::at::At;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::TraitEngineExt;
 use rustc_infer::traits::{FulfillmentError, Obligation, TraitEngine};
-use rustc_middle::infer::unify_key::ConstVariableOrigin;
 use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::{self, AliasTy, Ty, TyCtxt, UniverseIndex};
+use rustc_middle::ty::{self, Ty, TyCtxt, UniverseIndex};
 use rustc_middle::ty::{FallibleTypeFolder, TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::{TypeFoldable, TypeVisitableExt};
 
@@ -65,7 +63,7 @@
             };
 
             self.at.infcx.err_ctxt().report_overflow_error(
-                OverflowCause::DeeplyNormalize(data),
+                OverflowCause::DeeplyNormalize(data.into()),
                 self.at.cause.span,
                 true,
                 |_| {},
@@ -74,8 +72,7 @@
 
         self.depth += 1;
 
-        let new_infer_ty =
-            infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span: self.at.cause.span });
+        let new_infer_ty = infcx.next_ty_var(self.at.cause.span);
         let obligation = Obligation::new(
             tcx,
             self.at.cause.clone(),
@@ -111,7 +108,7 @@
         let recursion_limit = tcx.recursion_limit();
         if !recursion_limit.value_within_limit(self.depth) {
             self.at.infcx.err_ctxt().report_overflow_error(
-                OverflowCause::DeeplyNormalize(ty::AliasTy::new(tcx, uv.def, uv.args)),
+                OverflowCause::DeeplyNormalize(uv.into()),
                 self.at.cause.span,
                 true,
                 |_| {},
@@ -120,18 +117,12 @@
 
         self.depth += 1;
 
-        let new_infer_ct = infcx.next_const_var(
-            ty,
-            ConstVariableOrigin { param_def_id: None, span: self.at.cause.span },
-        );
+        let new_infer_ct = infcx.next_const_var(ty, self.at.cause.span);
         let obligation = Obligation::new(
             tcx,
             self.at.cause.clone(),
             self.at.param_env,
-            ty::NormalizesTo {
-                alias: AliasTy::new(tcx, uv.def, uv.args),
-                term: new_infer_ct.into(),
-            },
+            ty::NormalizesTo { alias: uv.into(), term: new_infer_ct.into() },
         );
 
         let result = if infcx.predicate_may_hold(&obligation) {
@@ -168,7 +159,7 @@
         Ok(t)
     }
 
-    #[instrument(level = "debug", skip(self), ret)]
+    #[instrument(level = "trace", skip(self), ret)]
     fn try_fold_ty(&mut self, ty: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
         let infcx = self.at.infcx;
         debug_assert_eq!(ty, infcx.shallow_resolve(ty));
@@ -195,7 +186,7 @@
         }
     }
 
-    #[instrument(level = "debug", skip(self), ret)]
+    #[instrument(level = "trace", skip(self), ret)]
     fn try_fold_const(&mut self, ct: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
         let infcx = self.at.infcx;
         debug_assert_eq!(ct, infcx.shallow_resolve_const(ct));
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs
index 37d5645..c9621e7 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs
@@ -1,9 +1,10 @@
 use crate::solve::EvalCtxt;
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
 use rustc_middle::ty;
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
-    #[instrument(level = "debug", skip(self), ret)]
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
+    #[instrument(level = "trace", skip(self), ret)]
     pub(super) fn normalize_anon_const(
         &mut self,
         goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
index 439f9ee..2146a2c 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs
@@ -4,18 +4,19 @@
 //! 1. instantiate generic parameters,
 //! 2. equate the self type, and
 //! 3. instantiate and register where clauses.
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
 use rustc_middle::ty;
 
 use crate::solve::EvalCtxt;
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     pub(super) fn normalize_inherent_associated_type(
         &mut self,
         goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
     ) -> QueryResult<'tcx> {
         let tcx = self.tcx();
-        let inherent = goal.predicate.alias;
+        let inherent = goal.predicate.alias.expect_ty(tcx);
 
         let impl_def_id = tcx.parent(inherent.def_id);
         let impl_args = self.fresh_args_for_item(impl_def_id);
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
index f886c58..7ef8373 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs
@@ -3,9 +3,9 @@
 use super::assembly::structural_traits::AsyncCallableRelevantTypes;
 use super::assembly::{self, structural_traits, Candidate};
 use super::{EvalCtxt, GoalSource};
-use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_hir::LangItem;
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::solve::inspect::ProbeKind;
 use rustc_infer::traits::solve::MaybeCause;
@@ -16,7 +16,8 @@
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::NormalizesTo;
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
+use rustc_middle::ty::{TypeVisitableExt, Upcast};
+use rustc_middle::{bug, span_bug};
 use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP};
 
 mod anon_const;
@@ -24,8 +25,8 @@
 mod opaque_types;
 mod weak_types;
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
-    #[instrument(level = "debug", skip(self), ret)]
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
+    #[instrument(level = "trace", skip(self), ret)]
     pub(super) fn compute_normalizes_to_goal(
         &mut self,
         goal: Goal<'tcx, NormalizesTo<'tcx>>,
@@ -40,47 +41,28 @@
             Ok(res) => Ok(res),
             Err(NoSolution) => {
                 let Goal { param_env, predicate: NormalizesTo { alias, term } } = goal;
-                if alias.opt_kind(self.tcx()).is_some() {
-                    self.relate_rigid_alias_non_alias(
-                        param_env,
-                        alias,
-                        ty::Variance::Invariant,
-                        term,
-                    )?;
-                    self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
-                } else {
-                    // FIXME(generic_const_exprs): we currently do not support rigid
-                    // unevaluated constants.
-                    Err(NoSolution)
-                }
+                self.relate_rigid_alias_non_alias(param_env, alias, ty::Variance::Invariant, term)?;
+                self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
             }
         }
     }
 
     /// Normalize the given alias by at least one step. If the alias is rigid, this
     /// returns `NoSolution`.
-    #[instrument(level = "debug", skip(self), ret)]
+    #[instrument(level = "trace", skip(self), ret)]
     fn normalize_at_least_one_step(
         &mut self,
         goal: Goal<'tcx, NormalizesTo<'tcx>>,
     ) -> QueryResult<'tcx> {
-        let def_id = goal.predicate.def_id();
-        match self.tcx().def_kind(def_id) {
-            DefKind::AssocTy | DefKind::AssocConst => {
-                match self.tcx().associated_item(def_id).container {
-                    ty::AssocItemContainer::TraitContainer => {
-                        let candidates = self.assemble_and_evaluate_candidates(goal);
-                        self.merge_candidates(candidates)
-                    }
-                    ty::AssocItemContainer::ImplContainer => {
-                        self.normalize_inherent_associated_type(goal)
-                    }
-                }
+        match goal.predicate.alias.kind(self.tcx()) {
+            ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => {
+                let candidates = self.assemble_and_evaluate_candidates(goal);
+                self.merge_candidates(candidates)
             }
-            DefKind::AnonConst => self.normalize_anon_const(goal),
-            DefKind::TyAlias => self.normalize_weak_type(goal),
-            DefKind::OpaqueTy => self.normalize_opaque_type(goal),
-            kind => bug!("unknown DefKind {} in normalizes-to goal: {goal:#?}", kind.descr(def_id)),
+            ty::AliasTermKind::InherentTy => self.normalize_inherent_associated_type(goal),
+            ty::AliasTermKind::OpaqueTy => self.normalize_opaque_type(goal),
+            ty::AliasTermKind::WeakTy => self.normalize_weak_type(goal),
+            ty::AliasTermKind::UnevaluatedConst => self.normalize_anon_const(goal),
         }
     }
 
@@ -117,11 +99,11 @@
     }
 
     fn probe_and_match_goal_against_assumption(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
-        source: CandidateSource,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
+        source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
-        then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
+        then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if let Some(projection_pred) = assumption.as_projection_clause() {
             if projection_pred.projection_def_id() == goal.predicate.def_id() {
@@ -132,7 +114,7 @@
                     ecx.eq(
                         goal.param_env,
                         goal.predicate.alias,
-                        assumption_projection_pred.projection_ty,
+                        assumption_projection_pred.projection_term,
                     )?;
 
                     ecx.instantiate_normalizes_to_term(goal, assumption_projection_pred.term);
@@ -156,7 +138,7 @@
     }
 
     fn consider_impl_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, NormalizesTo<'tcx>>,
         impl_def_id: DefId,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -218,7 +200,7 @@
                 return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
             };
 
-            let error_response = |ecx: &mut EvalCtxt<'_, 'tcx>, reason| {
+            let error_response = |ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, reason| {
                 let guar = tcx.dcx().span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason);
                 let error_term = match assoc_def.item.kind {
                     ty::AssocKind::Const => ty::Const::new_error(
@@ -298,14 +280,14 @@
     /// Fail to normalize if the predicate contains an error, alternatively, we could normalize to `ty::Error`
     /// and succeed. Can experiment with this to figure out what results in better error messages.
     fn consider_error_guaranteed_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         _guar: ErrorGuaranteed,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         Err(NoSolution)
     }
 
     fn consider_auto_trait_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         ecx.tcx().dcx().span_delayed_bug(
@@ -316,42 +298,42 @@
     }
 
     fn consider_trait_alias_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("trait aliases do not have associated types: {:?}", goal);
     }
 
     fn consider_builtin_sized_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`Sized` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_copy_clone_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`Copy`/`Clone` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_pointer_like_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`PointerLike` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_fn_ptr_trait_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`FnPtr` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_fn_trait_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
         goal_kind: ty::ClosureKind,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -368,19 +350,19 @@
                 }
             };
         let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
-            ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
+            ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output])
         });
 
         let pred = tupled_inputs_and_output
             .map_bound(|(inputs, output)| ty::ProjectionPredicate {
-                projection_ty: ty::AliasTy::new(
+                projection_term: ty::AliasTerm::new(
                     tcx,
                     goal.predicate.def_id(),
                     [goal.predicate.self_ty(), inputs],
                 ),
                 term: output.into(),
             })
-            .to_predicate(tcx);
+            .upcast(tcx);
 
         // A built-in `Fn` impl only holds if the output is sized.
         // (FIXME: technically we only need to check this if the type is a fn ptr...)
@@ -394,7 +376,7 @@
     }
 
     fn consider_builtin_async_fn_trait_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
         goal_kind: ty::ClosureKind,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -414,7 +396,7 @@
             )?;
         let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
             |AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| {
-                ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output_ty])
+                ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output_ty])
             },
         );
 
@@ -425,9 +407,9 @@
                      output_coroutine_ty,
                      coroutine_return_ty,
                  }| {
-                    let (projection_ty, term) = match tcx.item_name(goal.predicate.def_id()) {
+                    let (projection_term, term) = match tcx.item_name(goal.predicate.def_id()) {
                         sym::CallOnceFuture => (
-                            ty::AliasTy::new(
+                            ty::AliasTerm::new(
                                 tcx,
                                 goal.predicate.def_id(),
                                 [goal.predicate.self_ty(), tupled_inputs_ty],
@@ -435,7 +417,7 @@
                             output_coroutine_ty.into(),
                         ),
                         sym::CallRefFuture => (
-                            ty::AliasTy::new(
+                            ty::AliasTerm::new(
                                 tcx,
                                 goal.predicate.def_id(),
                                 [
@@ -447,7 +429,7 @@
                             output_coroutine_ty.into(),
                         ),
                         sym::Output => (
-                            ty::AliasTy::new(
+                            ty::AliasTerm::new(
                                 tcx,
                                 goal.predicate.def_id(),
                                 [
@@ -459,10 +441,10 @@
                         ),
                         name => bug!("no such associated type: {name}"),
                     };
-                    ty::ProjectionPredicate { projection_ty, term }
+                    ty::ProjectionPredicate { projection_term, term }
                 },
             )
-            .to_predicate(tcx);
+            .upcast(tcx);
 
         // A built-in `AsyncFn` impl only holds if the output is sized.
         // (FIXME: technically we only need to check this if the type is a fn ptr...)
@@ -479,7 +461,7 @@
     }
 
     fn consider_builtin_async_fn_kind_helper_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let [
@@ -526,14 +508,14 @@
     }
 
     fn consider_builtin_tuple_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`Tuple` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_pointee_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let tcx = ecx.tcx();
@@ -576,10 +558,9 @@
                     // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`.
                     // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't
                     // exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`.
-                    let sized_predicate = ty::TraitRef::from_lang_item(
+                    let sized_predicate = ty::TraitRef::new(
                         tcx,
-                        LangItem::Sized,
-                        DUMMY_SP,
+                        tcx.require_lang_item(LangItem::Sized, None),
                         [ty::GenericArg::from(goal.predicate.self_ty())],
                     );
                     // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`?
@@ -616,7 +597,7 @@
     }
 
     fn consider_builtin_future_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let self_ty = goal.predicate.self_ty();
@@ -637,10 +618,10 @@
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
             goal,
             ty::ProjectionPredicate {
-                projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
+                projection_term: ty::AliasTerm::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
                 term,
             }
-            .to_predicate(tcx),
+            .upcast(tcx),
             // Technically, we need to check that the future type is Sized,
             // but that's already proven by the coroutine being WF.
             [],
@@ -648,7 +629,7 @@
     }
 
     fn consider_builtin_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let self_ty = goal.predicate.self_ty();
@@ -669,10 +650,10 @@
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
             goal,
             ty::ProjectionPredicate {
-                projection_ty: ty::AliasTy::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
+                projection_term: ty::AliasTerm::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]),
                 term,
             }
-            .to_predicate(tcx),
+            .upcast(tcx),
             // Technically, we need to check that the iterator type is Sized,
             // but that's already proven by the generator being WF.
             [],
@@ -680,14 +661,14 @@
     }
 
     fn consider_builtin_fused_iterator_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`FusedIterator` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_async_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let self_ty = goal.predicate.self_ty();
@@ -723,7 +704,7 @@
     }
 
     fn consider_builtin_coroutine_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let self_ty = goal.predicate.self_ty();
@@ -753,14 +734,14 @@
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
             goal,
             ty::ProjectionPredicate {
-                projection_ty: ty::AliasTy::new(
+                projection_term: ty::AliasTerm::new(
                     ecx.tcx(),
                     goal.predicate.def_id(),
                     [self_ty, coroutine.resume_ty()],
                 ),
                 term,
             }
-            .to_predicate(tcx),
+            .upcast(tcx),
             // Technically, we need to check that the coroutine type is Sized,
             // but that's already proven by the coroutine being WF.
             [],
@@ -768,14 +749,14 @@
     }
 
     fn consider_structural_builtin_unsize_candidates(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Vec<Candidate<'tcx>> {
         bug!("`Unsize` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_discriminant_kind_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let self_ty = goal.predicate.self_ty();
@@ -827,7 +808,7 @@
     }
 
     fn consider_builtin_async_destruct_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let self_ty = goal.predicate.self_ty();
@@ -880,14 +861,14 @@
     }
 
     fn consider_builtin_destruct_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`Destruct` does not have an associated type: {:?}", goal);
     }
 
     fn consider_builtin_transmute_candidate(
-        _ecx: &mut EvalCtxt<'_, 'tcx>,
+        _ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         bug!("`BikeshedIntrinsicFrom` does not have an associated type: {:?}", goal)
@@ -898,9 +879,9 @@
 ///
 /// FIXME: We should merge these 3 implementations as it's likely that they otherwise
 /// diverge.
-#[instrument(level = "debug", skip(ecx, param_env), ret)]
+#[instrument(level = "trace", skip(ecx, param_env), ret)]
 fn fetch_eligible_assoc_item_def<'tcx>(
-    ecx: &EvalCtxt<'_, 'tcx>,
+    ecx: &EvalCtxt<'_, InferCtxt<'tcx>>,
     param_env: ty::ParamEnv<'tcx>,
     goal_trait_ref: ty::TraitRef<'tcx>,
     trait_assoc_def_id: DefId,
@@ -921,7 +902,7 @@
             let poly_trait_ref = ecx.resolve_vars_if_possible(goal_trait_ref);
             !poly_trait_ref.still_further_specializable()
         } else {
-            debug!(?node_item.item.def_id, "not eligible due to default");
+            trace!(?node_item.item.def_id, "not eligible due to default");
             false
         }
     };
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs
index 9fdb280..3b83d34 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs
@@ -1,6 +1,7 @@
 //! Computes a normalizes-to (projection) goal for opaque types. This goal
 //! behaves differently depending on the param-env's reveal mode and whether
 //! the opaque is in a defining scope.
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
 use rustc_middle::traits::Reveal;
@@ -9,7 +10,7 @@
 
 use crate::solve::{EvalCtxt, SolverMode};
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     pub(super) fn normalize_opaque_type(
         &mut self,
         goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs
index 13af506..109a9e9 100644
--- a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs
+++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs
@@ -3,12 +3,13 @@
 //!
 //! Since a weak alias is never ambiguous, this just computes the `type_of` of
 //! the alias and registers the where-clauses of the type alias.
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, QueryResult};
 use rustc_middle::ty;
 
 use crate::solve::EvalCtxt;
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     pub(super) fn normalize_weak_type(
         &mut self,
         goal: Goal<'tcx, ty::NormalizesTo<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 30ae385..8fa78e4 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -1,29 +1,18 @@
 use crate::solve::GoalSource;
 
 use super::EvalCtxt;
+use rustc_infer::infer::InferCtxt;
 use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
 use rustc_middle::ty::{self, ProjectionPredicate};
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
-    #[instrument(level = "debug", skip(self), ret)]
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
+    #[instrument(level = "trace", skip(self), ret)]
     pub(super) fn compute_projection_goal(
         &mut self,
         goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
     ) -> QueryResult<'tcx> {
         let tcx = self.tcx();
-        let projection_term = match goal.predicate.term.unpack() {
-            ty::TermKind::Ty(_) => goal.predicate.projection_ty.to_ty(tcx).into(),
-            ty::TermKind::Const(_) => ty::Const::new_unevaluated(
-                tcx,
-                ty::UnevaluatedConst::new(
-                    goal.predicate.projection_ty.def_id,
-                    goal.predicate.projection_ty.args,
-                ),
-                tcx.type_of(goal.predicate.projection_ty.def_id)
-                    .instantiate(tcx, goal.predicate.projection_ty.args),
-            )
-            .into(),
-        };
+        let projection_term = goal.predicate.projection_term.to_term(tcx);
         let goal = goal.with(
             tcx,
             ty::PredicateKind::AliasRelate(
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs
index a48b2f2..bcd210f 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs
@@ -1,18 +1,21 @@
-use crate::solve::FIXPOINT_STEP_LIMIT;
+use std::mem;
 
-use super::inspect;
-use super::inspect::ProofTreeBuilder;
-use super::SolverMode;
-use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_index::Idx;
 use rustc_index::IndexVec;
 use rustc_middle::dep_graph::dep_kinds;
 use rustc_middle::traits::solve::CacheData;
-use rustc_middle::traits::solve::{CanonicalInput, Certainty, EvaluationCache, QueryResult};
+use rustc_middle::traits::solve::EvaluationCache;
 use rustc_middle::ty::TyCtxt;
+use rustc_next_trait_solver::solve::{CanonicalInput, Certainty, QueryResult};
 use rustc_session::Limit;
-use std::mem;
+use rustc_type_ir::inherent::*;
+use rustc_type_ir::Interner;
+
+use super::inspect;
+use super::inspect::ProofTreeBuilder;
+use super::SolverMode;
+use crate::solve::FIXPOINT_STEP_LIMIT;
 
 rustc_index::newtype_index! {
     #[orderable]
@@ -30,9 +33,10 @@
     }
 }
 
-#[derive(Debug)]
-struct StackEntry<'tcx> {
-    input: CanonicalInput<'tcx>,
+#[derive(derivative::Derivative)]
+#[derivative(Debug(bound = ""))]
+struct StackEntry<I: Interner> {
+    input: CanonicalInput<I>,
 
     available_depth: Limit,
 
@@ -43,21 +47,40 @@
     /// Whether this entry is a non-root cycle participant.
     ///
     /// We must not move the result of non-root cycle participants to the
-    /// global cache. See [SearchGraph::cycle_participants] for more details.
-    /// We store the highest stack depth of a head of a cycle this goal is involved
-    /// in. This necessary to soundly cache its provisional result.
+    /// global cache. We store the highest stack depth of a head of a cycle
+    /// this goal is involved in. This necessary to soundly cache its
+    /// provisional result.
     non_root_cycle_participant: Option<StackDepth>,
 
     encountered_overflow: bool,
 
     has_been_used: HasBeenUsed,
+
+    /// We put only the root goal of a coinductive cycle into the global cache.
+    ///
+    /// If we were to use that result when later trying to prove another cycle
+    /// participant, we can end up with unstable query results.
+    ///
+    /// See tests/ui/next-solver/coinduction/incompleteness-unstable-result.rs for
+    /// an example of where this is needed.
+    ///
+    /// There can  be multiple roots on the same stack, so we need to track
+    /// cycle participants per root:
+    /// ```plain
+    /// A :- B
+    /// B :- A, C
+    /// C :- D
+    /// D :- C
+    /// ```
+    cycle_participants: FxHashSet<CanonicalInput<I>>,
     /// Starts out as `None` and gets set when rerunning this
     /// goal in case we encounter a cycle.
-    provisional_result: Option<QueryResult<'tcx>>,
+    provisional_result: Option<QueryResult<I>>,
 }
 
 /// The provisional result for a goal which is not on the stack.
-struct DetachedEntry<'tcx> {
+#[derive(Debug)]
+struct DetachedEntry<I: Interner> {
     /// The head of the smallest non-trivial cycle involving this entry.
     ///
     /// Given the following rules, when proving `A` the head for
@@ -68,7 +91,7 @@
     /// C :- A + B + C
     /// ```
     head: StackDepth,
-    result: QueryResult<'tcx>,
+    result: QueryResult<I>,
 }
 
 /// Stores the stack depth of a currently evaluated goal *and* already
@@ -83,14 +106,15 @@
 ///
 /// The provisional cache can theoretically result in changes to the observable behavior,
 /// see tests/ui/traits/next-solver/cycles/provisional-cache-impacts-behavior.rs.
-#[derive(Default)]
-struct ProvisionalCacheEntry<'tcx> {
+#[derive(derivative::Derivative)]
+#[derivative(Default(bound = ""))]
+struct ProvisionalCacheEntry<I: Interner> {
     stack_depth: Option<StackDepth>,
-    with_inductive_stack: Option<DetachedEntry<'tcx>>,
-    with_coinductive_stack: Option<DetachedEntry<'tcx>>,
+    with_inductive_stack: Option<DetachedEntry<I>>,
+    with_coinductive_stack: Option<DetachedEntry<I>>,
 }
 
-impl<'tcx> ProvisionalCacheEntry<'tcx> {
+impl<I: Interner> ProvisionalCacheEntry<I> {
     fn is_empty(&self) -> bool {
         self.stack_depth.is_none()
             && self.with_inductive_stack.is_none()
@@ -98,53 +122,30 @@
     }
 }
 
-pub(super) struct SearchGraph<'tcx> {
+pub(super) struct SearchGraph<I: Interner> {
     mode: SolverMode,
     /// The stack of goals currently being computed.
     ///
     /// An element is *deeper* in the stack if its index is *lower*.
-    stack: IndexVec<StackDepth, StackEntry<'tcx>>,
-    provisional_cache: FxHashMap<CanonicalInput<'tcx>, ProvisionalCacheEntry<'tcx>>,
-    /// We put only the root goal of a coinductive cycle into the global cache.
-    ///
-    /// If we were to use that result when later trying to prove another cycle
-    /// participant, we can end up with unstable query results.
-    ///
-    /// See tests/ui/next-solver/coinduction/incompleteness-unstable-result.rs for
-    /// an example of where this is needed.
-    cycle_participants: FxHashSet<CanonicalInput<'tcx>>,
+    stack: IndexVec<StackDepth, StackEntry<I>>,
+    provisional_cache: FxHashMap<CanonicalInput<I>, ProvisionalCacheEntry<I>>,
 }
 
-impl<'tcx> SearchGraph<'tcx> {
-    pub(super) fn new(mode: SolverMode) -> SearchGraph<'tcx> {
-        Self {
-            mode,
-            stack: Default::default(),
-            provisional_cache: Default::default(),
-            cycle_participants: Default::default(),
-        }
+impl<I: Interner> SearchGraph<I> {
+    pub(super) fn new(mode: SolverMode) -> SearchGraph<I> {
+        Self { mode, stack: Default::default(), provisional_cache: Default::default() }
     }
 
     pub(super) fn solver_mode(&self) -> SolverMode {
         self.mode
     }
 
-    /// Update the stack and reached depths on cache hits.
-    #[instrument(level = "debug", skip(self))]
-    fn on_cache_hit(&mut self, additional_depth: usize, encountered_overflow: bool) {
-        let reached_depth = self.stack.next_index().plus(additional_depth);
-        if let Some(last) = self.stack.raw.last_mut() {
-            last.reached_depth = last.reached_depth.max(reached_depth);
-            last.encountered_overflow |= encountered_overflow;
-        }
-    }
-
     /// Pops the highest goal from the stack, lazily updating the
     /// the next goal in the stack.
     ///
     /// Directly popping from the stack instead of using this method
     /// would cause us to not track overflow and recursion depth correctly.
-    fn pop_stack(&mut self) -> StackEntry<'tcx> {
+    fn pop_stack(&mut self) -> StackEntry<I> {
         let elem = self.stack.pop().unwrap();
         if let Some(last) = self.stack.raw.last_mut() {
             last.reached_depth = last.reached_depth.max(elem.reached_depth);
@@ -153,25 +154,8 @@
         elem
     }
 
-    /// The trait solver behavior is different for coherence
-    /// so we use a separate cache. Alternatively we could use
-    /// a single cache and share it between coherence and ordinary
-    /// trait solving.
-    pub(super) fn global_cache(&self, tcx: TyCtxt<'tcx>) -> &'tcx EvaluationCache<'tcx> {
-        match self.mode {
-            SolverMode::Normal => &tcx.new_solver_evaluation_cache,
-            SolverMode::Coherence => &tcx.new_solver_coherence_evaluation_cache,
-        }
-    }
-
     pub(super) fn is_empty(&self) -> bool {
-        if self.stack.is_empty() {
-            debug_assert!(self.provisional_cache.is_empty());
-            debug_assert!(self.cycle_participants.is_empty());
-            true
-        } else {
-            false
-        }
+        self.stack.is_empty()
     }
 
     /// Returns the remaining depth allowed for nested goals.
@@ -181,8 +165,8 @@
     /// the remaining depth of all nested goals to prevent hangs
     /// in case there is exponential blowup.
     fn allowed_depth_for_nested(
-        tcx: TyCtxt<'tcx>,
-        stack: &IndexVec<StackDepth, StackEntry<'tcx>>,
+        tcx: I,
+        stack: &IndexVec<StackDepth, StackEntry<I>>,
     ) -> Option<Limit> {
         if let Some(last) = stack.raw.last() {
             if last.available_depth.0 == 0 {
@@ -195,13 +179,13 @@
                 Limit(last.available_depth.0 - 1)
             })
         } else {
-            Some(tcx.recursion_limit())
+            Some(Limit(tcx.recursion_limit()))
         }
     }
 
     fn stack_coinductive_from(
-        tcx: TyCtxt<'tcx>,
-        stack: &IndexVec<StackDepth, StackEntry<'tcx>>,
+        tcx: I,
+        stack: &IndexVec<StackDepth, StackEntry<I>>,
         head: StackDepth,
     ) -> bool {
         stack.raw[head.index()..]
@@ -220,21 +204,32 @@
     // we reach a fixpoint and all other cycle participants to make sure that
     // their result does not get moved to the global cache.
     fn tag_cycle_participants(
-        stack: &mut IndexVec<StackDepth, StackEntry<'tcx>>,
-        cycle_participants: &mut FxHashSet<CanonicalInput<'tcx>>,
+        stack: &mut IndexVec<StackDepth, StackEntry<I>>,
         usage_kind: HasBeenUsed,
         head: StackDepth,
     ) {
         stack[head].has_been_used |= usage_kind;
         debug_assert!(!stack[head].has_been_used.is_empty());
-        for entry in &mut stack.raw[head.index() + 1..] {
+
+        // The current root of these cycles. Note that this may not be the final
+        // root in case a later goal depends on a goal higher up the stack.
+        let mut current_root = head;
+        while let Some(parent) = stack[current_root].non_root_cycle_participant {
+            current_root = parent;
+            debug_assert!(!stack[current_root].has_been_used.is_empty());
+        }
+
+        let (stack, cycle_participants) = stack.raw.split_at_mut(head.index() + 1);
+        let current_cycle_root = &mut stack[current_root.as_usize()];
+        for entry in cycle_participants {
             entry.non_root_cycle_participant = entry.non_root_cycle_participant.max(Some(head));
-            cycle_participants.insert(entry.input);
+            current_cycle_root.cycle_participants.insert(entry.input);
+            current_cycle_root.cycle_participants.extend(mem::take(&mut entry.cycle_participants));
         }
     }
 
     fn clear_dependent_provisional_results(
-        provisional_cache: &mut FxHashMap<CanonicalInput<'tcx>, ProvisionalCacheEntry<'tcx>>,
+        provisional_cache: &mut FxHashMap<CanonicalInput<I>, ProvisionalCacheEntry<I>>,
         head: StackDepth,
     ) {
         #[allow(rustc::potential_query_instability)]
@@ -244,6 +239,19 @@
             !entry.is_empty()
         });
     }
+}
+
+impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
+    /// The trait solver behavior is different for coherence
+    /// so we use a separate cache. Alternatively we could use
+    /// a single cache and share it between coherence and ordinary
+    /// trait solving.
+    pub(super) fn global_cache(&self, tcx: TyCtxt<'tcx>) -> &'tcx EvaluationCache<'tcx> {
+        match self.mode {
+            SolverMode::Normal => &tcx.new_solver_evaluation_cache,
+            SolverMode::Coherence => &tcx.new_solver_coherence_evaluation_cache,
+        }
+    }
 
     /// Probably the most involved method of the whole solver.
     ///
@@ -252,10 +260,14 @@
     pub(super) fn with_new_goal(
         &mut self,
         tcx: TyCtxt<'tcx>,
-        input: CanonicalInput<'tcx>,
-        inspect: &mut ProofTreeBuilder<'tcx>,
-        mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder<'tcx>) -> QueryResult<'tcx>,
-    ) -> QueryResult<'tcx> {
+        input: CanonicalInput<TyCtxt<'tcx>>,
+        inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+        mut prove_goal: impl FnMut(
+            &mut Self,
+            &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+        ) -> QueryResult<TyCtxt<'tcx>>,
+    ) -> QueryResult<TyCtxt<'tcx>> {
+        self.check_invariants();
         // Check for overflow.
         let Some(available_depth) = Self::allowed_depth_for_nested(tcx, &self.stack) else {
             if let Some(last) = self.stack.raw.last_mut() {
@@ -266,36 +278,7 @@
             return Self::response_no_constraints(tcx, input, Certainty::overflow(true));
         };
 
-        // Try to fetch the goal from the global cache.
-        'global: {
-            let Some(CacheData { result, proof_tree, reached_depth, encountered_overflow }) =
-                self.global_cache(tcx).get(
-                    tcx,
-                    input,
-                    |cycle_participants| {
-                        self.stack.iter().any(|entry| cycle_participants.contains(&entry.input))
-                    },
-                    available_depth,
-                )
-            else {
-                break 'global;
-            };
-
-            // If we're building a proof tree and the current cache entry does not
-            // contain a proof tree, we do not use the entry but instead recompute
-            // the goal. We simply overwrite the existing entry once we're done,
-            // caching the proof tree.
-            if !inspect.is_noop() {
-                if let Some(revisions) = proof_tree {
-                    inspect.goal_evaluation_kind(
-                        inspect::WipCanonicalGoalEvaluationKind::Interned { revisions },
-                    );
-                } else {
-                    break 'global;
-                }
-            }
-
-            self.on_cache_hit(reached_depth, encountered_overflow);
+        if let Some(result) = self.lookup_global_cache(tcx, input, available_depth, inspect) {
             return result;
         }
 
@@ -315,17 +298,13 @@
                     .filter(|p| !Self::stack_coinductive_from(tcx, &self.stack, p.head))
             })
         {
+            debug!("provisional cache hit");
             // We have a nested goal which is already in the provisional cache, use
             // its result. We do not provide any usage kind as that should have been
             // already set correctly while computing the cache entry.
             inspect
                 .goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::ProvisionalCacheHit);
-            Self::tag_cycle_participants(
-                &mut self.stack,
-                &mut self.cycle_participants,
-                HasBeenUsed::empty(),
-                entry.head,
-            );
+            Self::tag_cycle_participants(&mut self.stack, HasBeenUsed::empty(), entry.head);
             return entry.result;
         } else if let Some(stack_depth) = cache_entry.stack_depth {
             debug!("encountered cycle with depth {stack_depth:?}");
@@ -342,12 +321,7 @@
             } else {
                 HasBeenUsed::INDUCTIVE_CYCLE
             };
-            Self::tag_cycle_participants(
-                &mut self.stack,
-                &mut self.cycle_participants,
-                usage_kind,
-                stack_depth,
-            );
+            Self::tag_cycle_participants(&mut self.stack, usage_kind, stack_depth);
 
             // Return the provisional result or, if we're in the first iteration,
             // start with no constraints.
@@ -368,6 +342,7 @@
                 non_root_cycle_participant: None,
                 encountered_overflow: false,
                 has_been_used: HasBeenUsed::empty(),
+                cycle_participants: Default::default(),
                 provisional_result: None,
             };
             assert_eq!(self.stack.push(entry), depth);
@@ -376,63 +351,16 @@
 
         // This is for global caching, so we properly track query dependencies.
         // Everything that affects the `result` should be performed within this
-        // `with_anon_task` closure.
+        // `with_anon_task` closure. If computing this goal depends on something
+        // not tracked by the cache key and from outside of this anon task, it
+        // must not be added to the global cache. Notably, this is the case for
+        // trait solver cycles participants.
         let ((final_entry, result), dep_node) =
             tcx.dep_graph.with_anon_task(tcx, dep_kinds::TraitSelect, || {
-                // When we encounter a coinductive cycle, we have to fetch the
-                // result of that cycle while we are still computing it. Because
-                // of this we continuously recompute the cycle until the result
-                // of the previous iteration is equal to the final result, at which
-                // point we are done.
                 for _ in 0..FIXPOINT_STEP_LIMIT {
-                    let result = prove_goal(self, inspect);
-                    let stack_entry = self.pop_stack();
-                    debug_assert_eq!(stack_entry.input, input);
-
-                    // If the current goal is not the root of a cycle, we are done.
-                    if stack_entry.has_been_used.is_empty() {
-                        return (stack_entry, result);
-                    }
-
-                    // If it is a cycle head, we have to keep trying to prove it until
-                    // we reach a fixpoint. We need to do so for all cycle heads,
-                    // not only for the root.
-                    //
-                    // See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
-                    // for an example.
-
-                    // Start by clearing all provisional cache entries which depend on this
-                    // the current goal.
-                    Self::clear_dependent_provisional_results(
-                        &mut self.provisional_cache,
-                        self.stack.next_index(),
-                    );
-
-                    // Check whether we reached a fixpoint, either because the final result
-                    // is equal to the provisional result of the previous iteration, or because
-                    // this was only the root of either coinductive or inductive cycles, and the
-                    // final result is equal to the initial response for that case.
-                    let reached_fixpoint = if let Some(r) = stack_entry.provisional_result {
-                        r == result
-                    } else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE {
-                        Self::response_no_constraints(tcx, input, Certainty::Yes) == result
-                    } else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE {
-                        Self::response_no_constraints(tcx, input, Certainty::overflow(false))
-                            == result
-                    } else {
-                        false
-                    };
-
-                    // If we did not reach a fixpoint, update the provisional result and reevaluate.
-                    if reached_fixpoint {
-                        return (stack_entry, result);
-                    } else {
-                        let depth = self.stack.push(StackEntry {
-                            has_been_used: HasBeenUsed::empty(),
-                            provisional_result: Some(result),
-                            ..stack_entry
-                        });
-                        debug_assert_eq!(self.provisional_cache[&input].stack_depth, Some(depth));
+                    match self.fixpoint_step_in_task(tcx, input, inspect, &mut prove_goal) {
+                        StepResult::Done(final_entry, result) => return (final_entry, result),
+                        StepResult::HasChanged => {}
                     }
                 }
 
@@ -461,14 +389,13 @@
         } else {
             self.provisional_cache.remove(&input);
             let reached_depth = final_entry.reached_depth.as_usize() - self.stack.len();
-            let cycle_participants = mem::take(&mut self.cycle_participants);
             // When encountering a cycle, both inductive and coinductive, we only
             // move the root into the global cache. We also store all other cycle
             // participants involved.
             //
             // We must not use the global cache entry of a root goal if a cycle
             // participant is on the stack. This is necessary to prevent unstable
-            // results. See the comment of `SearchGraph::cycle_participants` for
+            // results. See the comment of `StackEntry::cycle_participants` for
             // more details.
             self.global_cache(tcx).insert(
                 tcx,
@@ -476,20 +403,208 @@
                 proof_tree,
                 reached_depth,
                 final_entry.encountered_overflow,
-                cycle_participants,
+                final_entry.cycle_participants,
                 dep_node,
                 result,
             )
         }
 
+        self.check_invariants();
+
         result
     }
 
+    /// Try to fetch a previously computed result from the global cache,
+    /// making sure to only do so if it would match the result of reevaluating
+    /// this goal.
+    fn lookup_global_cache(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        input: CanonicalInput<TyCtxt<'tcx>>,
+        available_depth: Limit,
+        inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+    ) -> Option<QueryResult<TyCtxt<'tcx>>> {
+        let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self
+            .global_cache(tcx)
+            .get(tcx, input, self.stack.iter().map(|e| e.input), available_depth)?;
+
+        // If we're building a proof tree and the current cache entry does not
+        // contain a proof tree, we do not use the entry but instead recompute
+        // the goal. We simply overwrite the existing entry once we're done,
+        // caching the proof tree.
+        if !inspect.is_noop() {
+            if let Some(revisions) = proof_tree {
+                let kind = inspect::WipCanonicalGoalEvaluationKind::Interned { revisions };
+                inspect.goal_evaluation_kind(kind);
+            } else {
+                return None;
+            }
+        }
+
+        // Update the reached depth of the current goal to make sure
+        // its state is the same regardless of whether we've used the
+        // global cache or not.
+        let reached_depth = self.stack.next_index().plus(additional_depth);
+        if let Some(last) = self.stack.raw.last_mut() {
+            last.reached_depth = last.reached_depth.max(reached_depth);
+            last.encountered_overflow |= encountered_overflow;
+        }
+
+        Some(result)
+    }
+}
+
+enum StepResult<I: Interner> {
+    Done(StackEntry<I>, QueryResult<I>),
+    HasChanged,
+}
+
+impl<'tcx> SearchGraph<TyCtxt<'tcx>> {
+    /// When we encounter a coinductive cycle, we have to fetch the
+    /// result of that cycle while we are still computing it. Because
+    /// of this we continuously recompute the cycle until the result
+    /// of the previous iteration is equal to the final result, at which
+    /// point we are done.
+    fn fixpoint_step_in_task<F>(
+        &mut self,
+        tcx: TyCtxt<'tcx>,
+        input: CanonicalInput<TyCtxt<'tcx>>,
+        inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>,
+        prove_goal: &mut F,
+    ) -> StepResult<TyCtxt<'tcx>>
+    where
+        F: FnMut(&mut Self, &mut ProofTreeBuilder<TyCtxt<'tcx>>) -> QueryResult<TyCtxt<'tcx>>,
+    {
+        let result = prove_goal(self, inspect);
+        let stack_entry = self.pop_stack();
+        debug_assert_eq!(stack_entry.input, input);
+
+        // If the current goal is not the root of a cycle, we are done.
+        if stack_entry.has_been_used.is_empty() {
+            return StepResult::Done(stack_entry, result);
+        }
+
+        // If it is a cycle head, we have to keep trying to prove it until
+        // we reach a fixpoint. We need to do so for all cycle heads,
+        // not only for the root.
+        //
+        // See tests/ui/traits/next-solver/cycles/fixpoint-rerun-all-cycle-heads.rs
+        // for an example.
+
+        // Start by clearing all provisional cache entries which depend on this
+        // the current goal.
+        Self::clear_dependent_provisional_results(
+            &mut self.provisional_cache,
+            self.stack.next_index(),
+        );
+
+        // Check whether we reached a fixpoint, either because the final result
+        // is equal to the provisional result of the previous iteration, or because
+        // this was only the root of either coinductive or inductive cycles, and the
+        // final result is equal to the initial response for that case.
+        let reached_fixpoint = if let Some(r) = stack_entry.provisional_result {
+            r == result
+        } else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE {
+            Self::response_no_constraints(tcx, input, Certainty::Yes) == result
+        } else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE {
+            Self::response_no_constraints(tcx, input, Certainty::overflow(false)) == result
+        } else {
+            false
+        };
+
+        // If we did not reach a fixpoint, update the provisional result and reevaluate.
+        if reached_fixpoint {
+            StepResult::Done(stack_entry, result)
+        } else {
+            let depth = self.stack.push(StackEntry {
+                has_been_used: HasBeenUsed::empty(),
+                provisional_result: Some(result),
+                ..stack_entry
+            });
+            debug_assert_eq!(self.provisional_cache[&input].stack_depth, Some(depth));
+            StepResult::HasChanged
+        }
+    }
+
     fn response_no_constraints(
         tcx: TyCtxt<'tcx>,
-        goal: CanonicalInput<'tcx>,
+        goal: CanonicalInput<TyCtxt<'tcx>>,
         certainty: Certainty,
-    ) -> QueryResult<'tcx> {
+    ) -> QueryResult<TyCtxt<'tcx>> {
         Ok(super::response_no_constraints_raw(tcx, goal.max_universe, goal.variables, certainty))
     }
 }
+
+impl<I: Interner> SearchGraph<I> {
+    #[allow(rustc::potential_query_instability)]
+    fn check_invariants(&self) {
+        if !cfg!(debug_assertions) {
+            return;
+        }
+
+        let SearchGraph { mode: _, stack, provisional_cache } = self;
+        if stack.is_empty() {
+            assert!(provisional_cache.is_empty());
+        }
+
+        for (depth, entry) in stack.iter_enumerated() {
+            let StackEntry {
+                input,
+                available_depth: _,
+                reached_depth: _,
+                non_root_cycle_participant,
+                encountered_overflow: _,
+                has_been_used,
+                ref cycle_participants,
+                provisional_result,
+            } = *entry;
+            let cache_entry = provisional_cache.get(&entry.input).unwrap();
+            assert_eq!(cache_entry.stack_depth, Some(depth));
+            if let Some(head) = non_root_cycle_participant {
+                assert!(head < depth);
+                assert!(cycle_participants.is_empty());
+                assert_ne!(stack[head].has_been_used, HasBeenUsed::empty());
+
+                let mut current_root = head;
+                while let Some(parent) = stack[current_root].non_root_cycle_participant {
+                    current_root = parent;
+                }
+                assert!(stack[current_root].cycle_participants.contains(&input));
+            }
+
+            if !cycle_participants.is_empty() {
+                assert!(provisional_result.is_some() || !has_been_used.is_empty());
+                for entry in stack.iter().take(depth.as_usize()) {
+                    assert_eq!(cycle_participants.get(&entry.input), None);
+                }
+            }
+        }
+
+        for (&input, entry) in &self.provisional_cache {
+            let ProvisionalCacheEntry { stack_depth, with_coinductive_stack, with_inductive_stack } =
+                entry;
+            assert!(
+                stack_depth.is_some()
+                    || with_coinductive_stack.is_some()
+                    || with_inductive_stack.is_some()
+            );
+
+            if let &Some(stack_depth) = stack_depth {
+                assert_eq!(stack[stack_depth].input, input);
+            }
+
+            let check_detached = |detached_entry: &DetachedEntry<I>| {
+                let DetachedEntry { head, result: _ } = *detached_entry;
+                assert_ne!(stack[head].has_been_used, HasBeenUsed::empty());
+            };
+
+            if let Some(with_coinductive_stack) = with_coinductive_stack {
+                check_detached(with_coinductive_stack);
+            }
+
+            if let Some(with_inductive_stack) = with_inductive_stack {
+                check_detached(with_inductive_stack);
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index 0fde9dd..e59eef2 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -8,15 +8,17 @@
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{LangItem, Movability};
+use rustc_infer::infer::InferCtxt;
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::traits::solve::MaybeCause;
+use rustc_middle::bug;
 use rustc_middle::traits::solve::inspect::ProbeKind;
 use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult};
 use rustc_middle::traits::{BuiltinImplSource, Reveal};
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt, Upcast};
 use rustc_middle::ty::{TraitPredicate, TypeVisitableExt};
-use rustc_span::{ErrorGuaranteed, DUMMY_SP};
+use rustc_span::ErrorGuaranteed;
 
 impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
     fn self_ty(self) -> Ty<'tcx> {
@@ -36,7 +38,7 @@
     }
 
     fn consider_impl_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
         impl_def_id: DefId,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -92,7 +94,7 @@
     }
 
     fn consider_error_guaranteed_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         _guar: ErrorGuaranteed,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         // FIXME: don't need to enter a probe here.
@@ -101,11 +103,11 @@
     }
 
     fn probe_and_match_goal_against_assumption(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
-        source: CandidateSource,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
+        source: CandidateSource<'tcx>,
         goal: Goal<'tcx, Self>,
         assumption: ty::Clause<'tcx>,
-        then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
+        then: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>) -> QueryResult<'tcx>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if let Some(trait_clause) = assumption.as_trait_clause() {
             if trait_clause.def_id() == goal.predicate.def_id()
@@ -129,7 +131,7 @@
     }
 
     fn consider_auto_trait_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -172,7 +174,7 @@
     }
 
     fn consider_trait_alias_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -195,7 +197,7 @@
     }
 
     fn consider_builtin_sized_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -210,7 +212,7 @@
     }
 
     fn consider_builtin_copy_clone_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -225,7 +227,7 @@
     }
 
     fn consider_builtin_pointer_like_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -255,7 +257,7 @@
     }
 
     fn consider_builtin_fn_ptr_trait_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let self_ty = goal.predicate.self_ty();
@@ -286,7 +288,7 @@
     }
 
     fn consider_builtin_fn_trait_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
         goal_kind: ty::ClosureKind,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -307,14 +309,14 @@
                 }
             };
         let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
-            ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
+            ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, None), [output])
         });
 
         let pred = tupled_inputs_and_output
             .map_bound(|(inputs, _)| {
                 ty::TraitRef::new(tcx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
             })
-            .to_predicate(tcx);
+            .upcast(tcx);
         // A built-in `Fn` impl only holds if the output is sized.
         // (FIXME: technically we only need to check this if the type is a fn ptr...)
         Self::probe_and_consider_implied_clause(
@@ -327,7 +329,7 @@
     }
 
     fn consider_builtin_async_fn_trait_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
         goal_kind: ty::ClosureKind,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -346,7 +348,11 @@
             )?;
         let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
             |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
-                ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output_coroutine_ty])
+                ty::TraitRef::new(
+                    tcx,
+                    tcx.require_lang_item(LangItem::Sized, None),
+                    [output_coroutine_ty],
+                )
             },
         );
 
@@ -358,7 +364,7 @@
                     [goal.predicate.self_ty(), tupled_inputs_ty],
                 )
             })
-            .to_predicate(tcx);
+            .upcast(tcx);
         // A built-in `AsyncFn` impl only holds if the output is sized.
         // (FIXME: technically we only need to check this if the type is a fn ptr...)
         Self::probe_and_consider_implied_clause(
@@ -374,7 +380,7 @@
     }
 
     fn consider_builtin_async_fn_kind_helper_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         let [closure_fn_kind_ty, goal_kind_ty] = **goal.predicate.trait_ref.args else {
@@ -401,7 +407,7 @@
     /// impl Tuple for (T1, .., Tn) {}
     /// ```
     fn consider_builtin_tuple_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -417,7 +423,7 @@
     }
 
     fn consider_builtin_pointee_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -429,7 +435,7 @@
     }
 
     fn consider_builtin_future_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -455,7 +461,7 @@
     }
 
     fn consider_builtin_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -481,7 +487,7 @@
     }
 
     fn consider_builtin_fused_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -505,7 +511,7 @@
     }
 
     fn consider_builtin_async_iterator_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -531,7 +537,7 @@
     }
 
     fn consider_builtin_coroutine_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -555,7 +561,7 @@
             CandidateSource::BuiltinImpl(BuiltinImplSource::Misc),
             goal,
             ty::TraitRef::new(tcx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()])
-                .to_predicate(tcx),
+                .upcast(tcx),
             // Technically, we need to check that the coroutine types are Sized,
             // but that's already proven by the coroutine being WF.
             [],
@@ -563,7 +569,7 @@
     }
 
     fn consider_builtin_discriminant_kind_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -576,7 +582,7 @@
     }
 
     fn consider_builtin_async_destruct_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -589,7 +595,7 @@
     }
 
     fn consider_builtin_destruct_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -605,7 +611,7 @@
     }
 
     fn consider_builtin_transmute_candidate(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -646,7 +652,7 @@
     /// impl<'a, T: Trait + 'a> Unsize<dyn Trait + 'a> for T {}
     /// ```
     fn consider_structural_builtin_unsize_candidates(
-        ecx: &mut EvalCtxt<'_, 'tcx>,
+        ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
         goal: Goal<'tcx, Self>,
     ) -> Vec<Candidate<'tcx>> {
         if goal.predicate.polarity != ty::PredicatePolarity::Positive {
@@ -717,7 +723,7 @@
     }
 }
 
-impl<'tcx> EvalCtxt<'_, 'tcx> {
+impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> {
     /// Trait upcasting allows for coercions between trait objects:
     /// ```ignore (builtin impl example)
     /// trait Super {}
@@ -816,7 +822,7 @@
     fn consider_builtin_upcast_to_principal(
         &mut self,
         goal: Goal<'tcx, (Ty<'tcx>, Ty<'tcx>)>,
-        source: CandidateSource,
+        source: CandidateSource<'tcx>,
         a_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
         a_region: ty::Region<'tcx>,
         b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>,
@@ -841,7 +847,7 @@
         // having any inference side-effects. We process obligations because
         // unification may initially succeed due to deferred projection equality.
         let projection_may_match =
-            |ecx: &mut EvalCtxt<'_, 'tcx>,
+            |ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>,
              source_projection: ty::PolyExistentialProjection<'tcx>,
              target_projection: ty::PolyExistentialProjection<'tcx>| {
                 source_projection.item_def_id() == target_projection.item_def_id()
@@ -1126,7 +1132,7 @@
                     },
                 );
                 if let Some(def_id) = disqualifying_impl {
-                    debug!(?def_id, ?goal, "disqualified auto-trait implementation");
+                    trace!(?def_id, ?goal, "disqualified auto-trait implementation");
                     // No need to actually consider the candidate here,
                     // since we do that in `consider_impl_candidate`.
                     return Some(Err(NoSolution));
@@ -1144,10 +1150,10 @@
     /// wrapped in one.
     fn probe_and_evaluate_goal_for_constituent_tys(
         &mut self,
-        source: CandidateSource,
+        source: CandidateSource<'tcx>,
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
         constituent_tys: impl Fn(
-            &EvalCtxt<'_, 'tcx>,
+            &EvalCtxt<'_, InferCtxt<'tcx>>,
             Ty<'tcx>,
         ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution>,
     ) -> Result<Candidate<'tcx>, NoSolution> {
@@ -1167,7 +1173,7 @@
         })
     }
 
-    #[instrument(level = "debug", skip(self))]
+    #[instrument(level = "trace", skip(self))]
     pub(super) fn compute_trait_goal(
         &mut self,
         goal: Goal<'tcx, TraitPredicate<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 053de2c..1ea207c 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -303,7 +303,7 @@
                 Err(SelectionError::Unimplemented) => {
                     if self.is_param_no_infer(pred.skip_binder().trait_ref.args) {
                         already_visited.remove(&pred);
-                        self.add_user_pred(&mut user_computed_preds, pred.to_predicate(self.tcx));
+                        self.add_user_pred(&mut user_computed_preds, pred.upcast(self.tcx));
                         predicates.push_back(pred);
                     } else {
                         debug!(
@@ -540,11 +540,11 @@
         finished_map
     }
 
-    fn is_param_no_infer(&self, args: GenericArgsRef<'_>) -> bool {
+    fn is_param_no_infer(&self, args: GenericArgsRef<'tcx>) -> bool {
         self.is_of_param(args.type_at(0)) && !args.types().any(|t| t.has_infer_types())
     }
 
-    pub fn is_of_param(&self, ty: Ty<'_>) -> bool {
+    pub fn is_of_param(&self, ty: Ty<'tcx>) -> bool {
         match ty.kind() {
             ty::Param(_) => true,
             ty::Alias(ty::Projection, p) => self.is_of_param(p.self_ty()),
@@ -552,9 +552,9 @@
         }
     }
 
-    fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool {
+    fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'tcx>) -> bool {
         if let Some(ty) = p.term().skip_binder().ty() {
-            matches!(ty.kind(), ty::Alias(ty::Projection, proj) if proj == &p.skip_binder().projection_ty)
+            matches!(ty.kind(), ty::Alias(ty::Projection, proj) if proj == &p.skip_binder().projection_term.expect_ty(self.tcx))
         } else {
             false
         }
@@ -612,7 +612,7 @@
                     // an inference variable.
                     // Additionally, we check if we've seen this predicate before,
                     // to avoid rendering duplicate bounds to the user.
-                    if self.is_param_no_infer(p.skip_binder().projection_ty.args)
+                    if self.is_param_no_infer(p.skip_binder().projection_term.args)
                         && !p.term().skip_binder().has_infer_types()
                         && is_new_pred
                     {
@@ -684,7 +684,7 @@
                     // and turn them into an explicit negative impl for our type.
                     debug!("Projecting and unifying projection predicate {:?}", predicate);
 
-                    match project::poly_project_and_unify_type(selcx, &obligation.with(self.tcx, p))
+                    match project::poly_project_and_unify_term(selcx, &obligation.with(self.tcx, p))
                     {
                         ProjectAndUnifyResult::MismatchedProjectionTypes(e) => {
                             debug!(
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 59725ce..ebdb032 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -20,6 +20,7 @@
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
 use rustc_infer::traits::{util, FulfillmentErrorCode};
+use rustc_middle::bug;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal};
 use rustc_middle::traits::specialization_graph::OverlapMode;
@@ -1095,11 +1096,11 @@
             Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(tr))) => tr.trait_ref,
             Some(ty::PredicateKind::Clause(ty::ClauseKind::Projection(proj)))
                 if matches!(
-                    infcx.tcx.def_kind(proj.projection_ty.def_id),
+                    infcx.tcx.def_kind(proj.projection_term.def_id),
                     DefKind::AssocTy | DefKind::AssocConst
                 ) =>
             {
-                proj.projection_ty.trait_ref(infcx.tcx)
+                proj.projection_term.trait_ref(infcx.tcx)
             }
             _ => return,
         };
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index a8be5627..8348482 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -11,6 +11,7 @@
 
 use rustc_hir::def::DefKind;
 use rustc_infer::infer::InferCtxt;
+use rustc_middle::bug;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 551c8e7..4684c71 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -25,8 +25,8 @@
 use rustc_middle::arena::ArenaAllocatable;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::TypeFoldable;
+use rustc_middle::ty::Upcast;
 use rustc_middle::ty::Variance;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 
@@ -96,7 +96,7 @@
             cause,
             recursion_depth: 0,
             param_env,
-            predicate: ty::Binder::dummy(trait_ref).to_predicate(tcx),
+            predicate: trait_ref.upcast(tcx),
         });
     }
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
index 9e5701f..4b5b1d7 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/infer_ctxt_ext.rs
@@ -1,4 +1,3 @@
-use crate::infer::type_variable::TypeVariableOrigin;
 use crate::infer::InferCtxt;
 use crate::traits::{Obligation, ObligationCause, ObligationCtxt};
 use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, Diag};
@@ -218,8 +217,7 @@
                 let Some(trait_def_id) = trait_def_id else { continue };
                 // Make a fresh inference variable so we can determine what the generic parameters
                 // of the trait are.
-                let var =
-                    self.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None });
+                let var = self.next_ty_var(DUMMY_SP);
                 // FIXME(effects)
                 let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]);
                 let obligation = Obligation::new(
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index f1eb5b7..32c8a45 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -10,6 +10,8 @@
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_macros::{extension, LintDiagnostic};
+use rustc_middle::bug;
+use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::GenericArgsRef;
 use rustc_middle::ty::{self, GenericParamDefKind, TyCtxt};
 use rustc_parse_format::{ParseMode, Parser, Piece, Position};
@@ -127,9 +129,9 @@
         flags.push((sym::ItemContext, enclosure));
 
         match obligation.cause.code() {
-            ObligationCauseCode::BuiltinDerivedObligation(..)
-            | ObligationCauseCode::ImplDerivedObligation(..)
-            | ObligationCauseCode::WellFormedDerivedObligation(..) => {}
+            ObligationCauseCode::BuiltinDerived(..)
+            | ObligationCauseCode::ImplDerived(..)
+            | ObligationCauseCode::WellFormedDerived(..) => {}
             _ => {
                 // this is a "direct", user-specified, rather than derived,
                 // obligation.
@@ -165,7 +167,7 @@
                 ));
             }
 
-            for param in generics.params.iter() {
+            for param in generics.own_params.iter() {
                 let value = match param.kind {
                     GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => {
                         args[param.index as usize].to_string()
@@ -203,9 +205,9 @@
 
             if self_ty.is_fn() {
                 let fn_sig = self_ty.fn_sig(self.tcx);
-                let shortname = match fn_sig.unsafety() {
-                    hir::Unsafety::Normal => "fn",
-                    hir::Unsafety::Unsafe => "unsafe fn",
+                let shortname = match fn_sig.safety() {
+                    hir::Safety::Safe => "fn",
+                    hir::Safety::Unsafe => "unsafe fn",
                 };
                 flags.push((sym::_Self, Some(shortname.to_owned())));
             }
@@ -350,12 +352,14 @@
         option_name: &'static str,
     ) {
         if let (Some(new_item), Some(old_item)) = (new, old) {
-            tcx.emit_node_span_lint(
-                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
-                new_item,
-                IgnoredDiagnosticOption { span: new_item, prev_span: old_item, option_name },
-            );
+            if let Some(item_def_id) = item_def_id.as_local() {
+                tcx.emit_node_span_lint(
+                    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                    tcx.local_def_id_to_hir_id(item_def_id),
+                    new_item,
+                    IgnoredDiagnosticOption { span: new_item, prev_span: old_item, option_name },
+                );
+            }
         }
     }
 }
@@ -639,30 +643,38 @@
                     AttrArgs::Eq(span, AttrArgsEq::Hir(expr)) => span.to(expr.span),
                 };
 
-                tcx.emit_node_span_lint(
-                    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                    tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
-                    report_span,
-                    MalformedOnUnimplementedAttrLint::new(report_span),
-                );
+                if let Some(item_def_id) = item_def_id.as_local() {
+                    tcx.emit_node_span_lint(
+                        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                        tcx.local_def_id_to_hir_id(item_def_id),
+                        report_span,
+                        MalformedOnUnimplementedAttrLint::new(report_span),
+                    );
+                }
                 Ok(None)
             }
         } else if is_diagnostic_namespace_variant {
             match &attr.kind {
                 AttrKind::Normal(p) if !matches!(p.item.args, AttrArgs::Empty) => {
-                    tcx.emit_node_span_lint(
-                        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                        tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
-                        attr.span,
-                        MalformedOnUnimplementedAttrLint::new(attr.span),
-                    );
+                    if let Some(item_def_id) = item_def_id.as_local() {
+                        tcx.emit_node_span_lint(
+                            UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                            tcx.local_def_id_to_hir_id(item_def_id),
+                            attr.span,
+                            MalformedOnUnimplementedAttrLint::new(attr.span),
+                        );
+                    }
                 }
-                _ => tcx.emit_node_span_lint(
-                    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                    tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
-                    attr.span,
-                    MissingOptionsForOnUnimplementedAttr,
-                ),
+                _ => {
+                    if let Some(item_def_id) = item_def_id.as_local() {
+                        tcx.emit_node_span_lint(
+                            UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                            tcx.local_def_id_to_hir_id(item_def_id),
+                            attr.span,
+                            MissingOptionsForOnUnimplementedAttr,
+                        )
+                    }
+                }
             };
 
             Ok(None)
@@ -791,12 +803,14 @@
                             || format_spec.precision_span.is_some()
                             || format_spec.fill_span.is_some())
                     {
-                        tcx.emit_node_span_lint(
-                            UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                            tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
-                            self.span,
-                            InvalidFormatSpecifier,
-                        );
+                        if let Some(item_def_id) = item_def_id.as_local() {
+                            tcx.emit_node_span_lint(
+                                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                                tcx.local_def_id_to_hir_id(item_def_id),
+                                self.span,
+                                InvalidFormatSpecifier,
+                            );
+                        }
                     }
                     match a.position {
                         Position::ArgumentNamed(s) => {
@@ -809,18 +823,20 @@
                                     ()
                                 }
                                 // So is `{A}` if A is a type parameter
-                                s if generics.params.iter().any(|param| param.name == s) => (),
+                                s if generics.own_params.iter().any(|param| param.name == s) => (),
                                 s => {
                                     if self.is_diagnostic_namespace_variant {
-                                        tcx.emit_node_span_lint(
-                                            UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                                            tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
-                                            self.span,
-                                            UnknownFormatParameterForOnUnimplementedAttr {
-                                                argument_name: s,
-                                                trait_name,
-                                            },
-                                        );
+                                        if let Some(item_def_id) = item_def_id.as_local() {
+                                            tcx.emit_node_span_lint(
+                                                UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                                                tcx.local_def_id_to_hir_id(item_def_id),
+                                                self.span,
+                                                UnknownFormatParameterForOnUnimplementedAttr {
+                                                    argument_name: s,
+                                                    trait_name,
+                                                },
+                                            );
+                                        }
                                     } else {
                                         result = Err(struct_span_code_err!(
                                             tcx.dcx(),
@@ -842,12 +858,14 @@
                         // `{:1}` and `{}` are not to be used
                         Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => {
                             if self.is_diagnostic_namespace_variant {
-                                tcx.emit_node_span_lint(
-                                    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                                    tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
-                                    self.span,
-                                    DisallowedPositionalArgument,
-                                );
+                                if let Some(item_def_id) = item_def_id.as_local() {
+                                    tcx.emit_node_span_lint(
+                                        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                                        tcx.local_def_id_to_hir_id(item_def_id),
+                                        self.span,
+                                        DisallowedPositionalArgument,
+                                    );
+                                }
                             } else {
                                 let reported = struct_span_code_err!(
                                     tcx.dcx(),
@@ -870,12 +888,14 @@
         // so that users are aware that something is not correct
         for e in parser.errors {
             if self.is_diagnostic_namespace_variant {
-                tcx.emit_node_span_lint(
-                    UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
-                    tcx.local_def_id_to_hir_id(item_def_id.expect_local()),
-                    self.span,
-                    WrappedParserError { description: e.description, label: e.label },
-                );
+                if let Some(item_def_id) = item_def_id.as_local() {
+                    tcx.emit_node_span_lint(
+                        UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
+                        tcx.local_def_id_to_hir_id(item_def_id),
+                        self.span,
+                        WrappedParserError { description: e.description, label: e.label },
+                    );
+                }
             } else {
                 let reported =
                     struct_span_code_err!(tcx.dcx(), self.span, E0231, "{}", e.description,).emit();
@@ -897,7 +917,7 @@
         let trait_str = tcx.def_path_str(trait_ref.def_id);
         let generics = tcx.generics_of(trait_ref.def_id);
         let generic_map = generics
-            .params
+            .own_params
             .iter()
             .filter_map(|param| {
                 let value = match param.kind {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 3d2574a..6c56ebb 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -7,7 +7,7 @@
 
 use crate::errors;
 use crate::infer::InferCtxt;
-use crate::traits::{ImplDerivedObligationCause, NormalizeExt, ObligationCtxt};
+use crate::traits::{ImplDerivedCause, NormalizeExt, ObligationCtxt};
 
 use hir::def::CtorOf;
 use rustc_data_structures::fx::FxHashSet;
@@ -24,7 +24,6 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, HirId, Node};
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes, InferOk};
 use rustc_macros::extension;
 use rustc_middle::hir::map;
@@ -32,9 +31,10 @@
 use rustc_middle::ty::error::TypeError::{self, Sorts};
 use rustc_middle::ty::{
     self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind, GenericArgs,
-    InferTy, IsSuggestable, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
-    TypeVisitableExt, TypeckResults,
+    InferTy, IsSuggestable, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
+    TypeVisitableExt, TypeckResults, Upcast,
 };
+use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP};
@@ -46,7 +46,10 @@
 use crate::infer::InferCtxtExt as _;
 use crate::traits::error_reporting::type_err_ctxt_ext::InferCtxtPrivExt;
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
-use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
+use rustc_middle::ty::print::{
+    with_forced_trimmed_paths, with_no_trimmed_paths, PrintPolyTraitPredicateExt as _,
+    PrintTraitPredicateExt as _,
+};
 
 use itertools::EitherOrBoth;
 use itertools::Itertools;
@@ -190,7 +193,7 @@
             },
             // `fn foo(t: impl Trait)`
             //                       ^ suggest `where <T as Trait>::A: Bound`
-            predicate_constraint(hir_generics, trait_pred.to_predicate(tcx)),
+            predicate_constraint(hir_generics, trait_pred.upcast(tcx)),
         ];
         sugg.extend(ty_spans.into_iter().map(|s| (s, type_param_name.to_string())));
 
@@ -213,7 +216,7 @@
                 .find(|p| !matches!(p.kind, hir::GenericParamKind::Type { synthetic: true, .. })),
             super_traits,
         ) {
-            (_, None) => predicate_constraint(hir_generics, trait_pred.to_predicate(tcx)),
+            (_, None) => predicate_constraint(hir_generics, trait_pred.upcast(tcx)),
             (None, Some((ident, []))) => (
                 ident.span.shrink_to_hi(),
                 format!(": {}", trait_pred.print_modifiers_and_trait_path()),
@@ -456,8 +459,7 @@
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
         let mut code = obligation.cause.code();
-        if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, call_hir_id, .. } =
-            code
+        if let ObligationCauseCode::FunctionArg { arg_hir_id, call_hir_id, .. } = code
             && let Some(typeck_results) = &self.typeck_results
             && let hir::Node::Expr(expr) = self.tcx.hir_node(*arg_hir_id)
             && let Some(arg_ty) = typeck_results.expr_ty_adjusted_opt(expr)
@@ -539,10 +541,12 @@
                             self.tcx,
                             obligation.cause.clone(),
                             obligation.param_env,
-                            ty::TraitRef::from_lang_item(
+                            ty::TraitRef::new(
                                 self.tcx,
-                                hir::LangItem::Sized,
-                                obligation.cause.span,
+                                self.tcx.require_lang_item(
+                                    hir::LangItem::Sized,
+                                    Some(obligation.cause.span),
+                                ),
                                 [base_ty],
                             ),
                         );
@@ -847,7 +851,7 @@
             .collect::<Vec<_>>()
             .join(", ");
 
-        if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArgumentObligation { .. })
+        if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArg { .. })
             && obligation.cause.span.can_be_used_for_suggestions()
         {
             // When the obligation error has been ensured to have been caused by
@@ -981,8 +985,7 @@
             };
             let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false };
             let ty::Param(param) = inner_ty.kind() else { return false };
-            let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
-                obligation.cause.code()
+            let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()
             else {
                 return false;
             };
@@ -1103,9 +1106,9 @@
                             .iter()
                             .find_map(|pred| {
                                 if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
-                        && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
+                        && Some(proj.projection_term.def_id) == self.tcx.lang_items().fn_once_output()
                         // args tuple will always be args[1]
-                        && let ty::Tuple(args) = proj.projection_ty.args.type_at(1).kind()
+                        && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
                                 {
                                     Some((
                                         DefIdOrName::DefId(def_id),
@@ -1147,10 +1150,10 @@
                         };
                         param_env.caller_bounds().iter().find_map(|pred| {
                             if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
-                        && Some(proj.projection_ty.def_id) == self.tcx.lang_items().fn_once_output()
-                        && proj.projection_ty.self_ty() == found
+                        && Some(proj.projection_term.def_id) == self.tcx.lang_items().fn_once_output()
+                        && proj.projection_term.self_ty() == found
                         // args tuple will always be args[1]
-                        && let ty::Tuple(args) = proj.projection_ty.args.type_at(1).kind()
+                        && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
                             {
                                 Some((
                                     name,
@@ -1205,9 +1208,14 @@
         let span = obligation.cause.span;
 
         let code = match obligation.cause.code() {
-            ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => parent_code,
-            c @ ObligationCauseCode::ItemObligation(_)
-            | c @ ObligationCauseCode::ExprItemObligation(..) => c,
+            ObligationCauseCode::FunctionArg { parent_code, .. } => parent_code,
+            // FIXME(compiler-errors): This is kind of a mess, but required for obligations
+            // that come from a path expr to affect the *call* expr.
+            c @ ObligationCauseCode::WhereClauseInExpr(_, _, hir_id, _)
+                if self.tcx.hir().span(*hir_id).lo() == span.lo() =>
+            {
+                c
+            }
             c if matches!(
                 span.ctxt().outer_expn_data().kind,
                 ExpnKind::Desugaring(DesugaringKind::ForLoop)
@@ -1263,8 +1271,7 @@
             let mut_ref_self_ty_satisfies_pred = mk_result(trait_pred_and_mut_ref);
 
             let (ref_inner_ty_satisfies_pred, ref_inner_ty_mut) =
-                if let ObligationCauseCode::ItemObligation(_)
-                | ObligationCauseCode::ExprItemObligation(..) = obligation.cause.code()
+                if let ObligationCauseCode::WhereClauseInExpr(..) = obligation.cause.code()
                     && let ty::Ref(_, ty, mutability) = old_pred.self_ty().skip_binder().kind()
                 {
                     (
@@ -1402,12 +1409,10 @@
             return false;
         };
 
-        if let ObligationCauseCode::ImplDerivedObligation(cause) = &*code {
+        if let ObligationCauseCode::ImplDerived(cause) = &*code {
             try_borrowing(cause.derived.parent_trait_pred, &[])
-        } else if let ObligationCauseCode::BindingObligation(_, _)
-        | ObligationCauseCode::ItemObligation(_)
-        | ObligationCauseCode::ExprItemObligation(..)
-        | ObligationCauseCode::ExprBindingObligation(..) = code
+        } else if let ObligationCauseCode::WhereClause(..)
+        | ObligationCauseCode::WhereClauseInExpr(..) = code
         {
             try_borrowing(poly_trait_pred, &never_suggest_borrow)
         } else {
@@ -1645,10 +1650,8 @@
         err: &mut Diag<'_>,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) {
-        let points_at_arg = matches!(
-            obligation.cause.code(),
-            ObligationCauseCode::FunctionArgumentObligation { .. },
-        );
+        let points_at_arg =
+            matches!(obligation.cause.code(), ObligationCauseCode::FunctionArg { .. },);
 
         let span = obligation.cause.span;
         if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
@@ -1893,18 +1896,17 @@
                 ty::Tuple(inputs) if infcx.tcx.is_fn_trait(trait_ref.def_id) => {
                     infcx.tcx.mk_fn_sig(
                         *inputs,
-                        infcx
-                            .next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }),
+                        infcx.next_ty_var(DUMMY_SP),
                         false,
-                        hir::Unsafety::Normal,
+                        hir::Safety::Safe,
                         abi::Abi::Rust,
                     )
                 }
                 _ => infcx.tcx.mk_fn_sig(
                     [inputs],
-                    infcx.next_ty_var(TypeVariableOrigin { span: DUMMY_SP, param_def_id: None }),
+                    infcx.next_ty_var(DUMMY_SP),
                     false,
-                    hir::Unsafety::Normal,
+                    hir::Safety::Safe,
                     abi::Abi::Rust,
                 ),
             };
@@ -1955,7 +1957,7 @@
         found: Ty<'tcx>,
         param_env: ty::ParamEnv<'tcx>,
     ) {
-        let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } = cause else {
+        let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = cause else {
             return;
         };
         let ty::FnPtr(expected) = expected.kind() else {
@@ -2106,10 +2108,10 @@
         cause: &ObligationCauseCode<'tcx>,
         err: &mut Diag<'tcx>,
     ) {
-        // First, look for an `ExprBindingObligation`, which means we can get
+        // First, look for an `WhereClauseInExpr`, which means we can get
         // the uninstantiated predicate list of the called function. And check
         // that the predicate that we failed to satisfy is a `Fn`-like trait.
-        if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = cause
+        if let ObligationCauseCode::WhereClauseInExpr(def_id, _, _, idx) = cause
             && let predicates = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx)
             && let Some(pred) = predicates.predicates.get(*idx)
             && let ty::ClauseKind::Trait(trait_pred) = pred.kind().skip_binder()
@@ -2263,10 +2265,10 @@
         while let Some(code) = next_code {
             debug!(?code);
             match code {
-                ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
+                ObligationCauseCode::FunctionArg { parent_code, .. } => {
                     next_code = Some(parent_code);
                 }
-                ObligationCauseCode::ImplDerivedObligation(cause) => {
+                ObligationCauseCode::ImplDerived(cause) => {
                     let ty = cause.derived.parent_trait_pred.skip_binder().self_ty();
                     debug!(
                         parent_trait_ref = ?cause.derived.parent_trait_pred,
@@ -2295,8 +2297,8 @@
 
                     next_code = Some(&cause.derived.parent_code);
                 }
-                ObligationCauseCode::WellFormedDerivedObligation(derived_obligation)
-                | ObligationCauseCode::BuiltinDerivedObligation(derived_obligation) => {
+                ObligationCauseCode::WellFormedDerived(derived_obligation)
+                | ObligationCauseCode::BuiltinDerived(derived_obligation) => {
                     let ty = derived_obligation.parent_trait_pred.skip_binder().self_ty();
                     debug!(
                         parent_trait_ref = ?derived_obligation.parent_trait_pred,
@@ -2702,12 +2704,12 @@
         obligated_types: &mut Vec<Ty<'tcx>>,
         seen_requirements: &mut FxHashSet<DefId>,
     ) where
-        T: ToPredicate<'tcx>,
+        T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
     {
         let mut long_ty_file = None;
 
         let tcx = self.tcx;
-        let predicate = predicate.to_predicate(tcx);
+        let predicate = predicate.upcast(tcx);
         match *cause_code {
             ObligationCauseCode::ExprAssignable
             | ObligationCauseCode::MatchExpressionArm { .. }
@@ -2721,7 +2723,7 @@
             | ObligationCauseCode::MethodReceiver
             | ObligationCauseCode::ReturnNoExpression
             | ObligationCauseCode::UnifyReceiver(..)
-            | ObligationCauseCode::MiscObligation
+            | ObligationCauseCode::Misc
             | ObligationCauseCode::WellFormed(..)
             | ObligationCauseCode::MatchImpl(..)
             | ObligationCauseCode::ReturnValue(_)
@@ -2738,7 +2740,7 @@
             | ObligationCauseCode::ReferenceOutlivesReferent(..)
             | ObligationCauseCode::ObjectTypeBound(..) => {}
             ObligationCauseCode::RustCall => {
-                if let Some(pred) = predicate.to_opt_poly_trait_pred()
+                if let Some(pred) = predicate.as_trait_clause()
                     && Some(pred.def_id()) == tcx.lang_items().sized_trait()
                 {
                     err.note("argument required to be sized due to `extern \"rust-call\"` ABI");
@@ -2750,13 +2752,10 @@
             ObligationCauseCode::TupleElem => {
                 err.note("only the last element of a tuple may have a dynamically sized type");
             }
-            ObligationCauseCode::ItemObligation(_)
-            | ObligationCauseCode::ExprItemObligation(..) => {
-                // We hold the `DefId` of the item introducing the obligation, but displaying it
-                // doesn't add user usable information. It always point at an associated item.
-            }
-            ObligationCauseCode::BindingObligation(item_def_id, span)
-            | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..) => {
+            ObligationCauseCode::WhereClause(item_def_id, span)
+            | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)
+                if !span.is_dummy() =>
+            {
                 let item_name = tcx.def_path_str(item_def_id);
                 let short_item_name = with_forced_trimmed_paths!(tcx.def_path_str(item_def_id));
                 let mut multispan = MultiSpan::from(span);
@@ -2799,7 +2798,7 @@
                         // Check if this is an implicit bound, even in foreign crates.
                         if tcx
                             .generics_of(item_def_id)
-                            .params
+                            .own_params
                             .iter()
                             .any(|param| tcx.def_span(param.def_id) == span)
                         {
@@ -2887,6 +2886,10 @@
                     err.help(help);
                 }
             }
+            ObligationCauseCode::WhereClause(..) | ObligationCauseCode::WhereClauseInExpr(..) => {
+                // We hold the `DefId` of the item introducing the obligation, but displaying it
+                // doesn't add user usable information. It always point at an associated item.
+            }
             ObligationCauseCode::Coercion { source, target } => {
                 let source =
                     tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut long_ty_file);
@@ -3177,7 +3180,7 @@
             ObligationCauseCode::SharedStatic => {
                 err.note("shared static variables must have a type that implements `Sync`");
             }
-            ObligationCauseCode::BuiltinDerivedObligation(ref data) => {
+            ObligationCauseCode::BuiltinDerived(ref data) => {
                 let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
                 let ty = parent_trait_ref.skip_binder().self_ty();
                 if parent_trait_ref.references_error() {
@@ -3192,8 +3195,7 @@
                 let is_upvar_tys_infer_tuple = if !matches!(ty.kind(), ty::Tuple(..)) {
                     false
                 } else {
-                    if let ObligationCauseCode::BuiltinDerivedObligation(data) = &*data.parent_code
-                    {
+                    if let ObligationCauseCode::BuiltinDerived(data) = &*data.parent_code {
                         let parent_trait_ref =
                             self.resolve_vars_if_possible(data.parent_trait_pred);
                         let nested_ty = parent_trait_ref.skip_binder().self_ty();
@@ -3299,7 +3301,7 @@
                     });
                 }
             }
-            ObligationCauseCode::ImplDerivedObligation(ref data) => {
+            ObligationCauseCode::ImplDerived(ref data) => {
                 let mut parent_trait_pred =
                     self.resolve_vars_if_possible(data.derived.parent_trait_pred);
                 let parent_def_id = parent_trait_pred.def_id();
@@ -3369,9 +3371,7 @@
                 if is_auto_trait {
                     // We don't want to point at the ADT saying "required because it appears within
                     // the type `X`", like we would otherwise do in test `supertrait-auto-trait.rs`.
-                    while let ObligationCauseCode::BuiltinDerivedObligation(derived) =
-                        &*data.parent_code
-                    {
+                    while let ObligationCauseCode::BuiltinDerived(derived) = &*data.parent_code {
                         let child_trait_ref =
                             self.resolve_vars_if_possible(derived.parent_trait_pred);
                         let child_def_id = child_trait_ref.def_id();
@@ -3379,11 +3379,11 @@
                             break;
                         }
                         data = derived;
-                        parent_predicate = child_trait_ref.to_predicate(tcx);
+                        parent_predicate = child_trait_ref.upcast(tcx);
                         parent_trait_pred = child_trait_ref;
                     }
                 }
-                while let ObligationCauseCode::ImplDerivedObligation(child) = &*data.parent_code {
+                while let ObligationCauseCode::ImplDerived(child) = &*data.parent_code {
                     // Skip redundant recursive obligation notes. See `ui/issue-20413.rs`.
                     let child_trait_pred =
                         self.resolve_vars_if_possible(child.derived.parent_trait_pred);
@@ -3393,7 +3393,7 @@
                     }
                     count += 1;
                     data = &child.derived;
-                    parent_predicate = child_trait_pred.to_predicate(tcx);
+                    parent_predicate = child_trait_pred.upcast(tcx);
                     parent_trait_pred = child_trait_pred;
                 }
                 if count > 0 {
@@ -3424,7 +3424,7 @@
                     )
                 });
             }
-            ObligationCauseCode::WellFormedDerivedObligation(ref data) => {
+            ObligationCauseCode::WellFormedDerived(ref data) => {
                 let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
                 let parent_predicate = parent_trait_ref;
                 // #74711: avoid a stack overflow
@@ -3460,11 +3460,8 @@
                     format!("required by a bound on the type alias `{}`", tcx.item_name(def_id)),
                 );
             }
-            ObligationCauseCode::FunctionArgumentObligation {
-                arg_hir_id,
-                call_hir_id,
-                ref parent_code,
-                ..
+            ObligationCauseCode::FunctionArg {
+                arg_hir_id, call_hir_id, ref parent_code, ..
             } => {
                 self.note_function_argument_obligation(
                     body_id,
@@ -3487,7 +3484,7 @@
                     )
                 });
             }
-            ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => {
+            ObligationCauseCode::CompareImplItem { trait_item_def_id, kind, .. } => {
                 let item_name = tcx.item_name(trait_item_def_id);
                 let msg = format!(
                     "the requirement `{predicate}` appears on the `impl`'s {kind} \
@@ -3696,7 +3693,7 @@
         err: &mut Diag<'_>,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) {
-        if let ObligationCauseCode::ImplDerivedObligation(_) = obligation.cause.code()
+        if let ObligationCauseCode::ImplDerived(_) = obligation.cause.code()
             && self
                 .tcx
                 .is_diagnostic_item(sym::SliceIndex, trait_pred.skip_binder().trait_ref.def_id)
@@ -3729,7 +3726,7 @@
         {
             if let hir::Expr { kind: hir::ExprKind::MethodCall(_, rcvr, _, _), .. } = expr
                 && let Some(ty) = typeck_results.node_type_opt(rcvr.hir_id)
-                && let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
+                && let Some(failed_pred) = failed_pred.as_trait_clause()
                 && let pred = failed_pred.map_bound(|pred| pred.with_self_ty(tcx, ty))
                 && self.predicate_must_hold_modulo_regions(&Obligation::misc(
                     tcx, expr.span, body_id, param_env, pred,
@@ -3813,14 +3810,14 @@
             // to an associated type (as seen from `trait_pred`) in the predicate. Like in
             // trait_pred `S: Sum<<Self as Iterator>::Item>` and predicate `i32: Sum<&()>`
             let mut type_diffs = vec![];
-            if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code
+            if let ObligationCauseCode::WhereClauseInExpr(def_id, _, _, idx) = parent_code
                 && let Some(node_args) = typeck_results.node_args_opt(call_hir_id)
                 && let where_clauses =
                     self.tcx.predicates_of(def_id).instantiate(self.tcx, node_args)
                 && let Some(where_pred) = where_clauses.predicates.get(*idx)
             {
                 if let Some(where_pred) = where_pred.as_trait_clause()
-                    && let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
+                    && let Some(failed_pred) = failed_pred.as_trait_clause()
                 {
                     self.enter_forall(where_pred, |where_pred| {
                         let failed_pred = self.instantiate_binder_with_fresh_vars(
@@ -3846,15 +3843,15 @@
                         }
                     })
                 } else if let Some(where_pred) = where_pred.as_projection_clause()
-                    && let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred()
+                    && let Some(failed_pred) = failed_pred.as_projection_clause()
                     && let Some(found) = failed_pred.skip_binder().term.ty()
                 {
                     type_diffs = vec![Sorts(ty::error::ExpectedFound {
-                        expected: Ty::new_alias(
-                            self.tcx,
-                            ty::Projection,
-                            where_pred.skip_binder().projection_ty,
-                        ),
+                        expected: where_pred
+                            .skip_binder()
+                            .projection_term
+                            .expect_ty(self.tcx)
+                            .to_ty(self.tcx),
                         found,
                     })];
                 }
@@ -3929,7 +3926,7 @@
             && let fn_sig @ ty::FnSig {
                 abi: abi::Abi::Rust,
                 c_variadic: false,
-                unsafety: hir::Unsafety::Normal,
+                safety: hir::Safety::Safe,
                 ..
             } = fn_ty.fn_sig(tcx).skip_binder()
 
@@ -4046,10 +4043,9 @@
                         let node = tcx.hir_node_by_def_id(hir.get_parent_item(expr.hir_id).def_id);
 
                         let pred = ty::Binder::dummy(ty::TraitPredicate {
-                            trait_ref: ty::TraitRef::from_lang_item(
+                            trait_ref: ty::TraitRef::new(
                                 tcx,
-                                LangItem::Clone,
-                                span,
+                                tcx.require_lang_item(LangItem::Clone, Some(span)),
                                 [*ty],
                             ),
                             polarity: ty::PredicatePolarity::Positive,
@@ -4263,7 +4259,6 @@
                 continue;
             };
 
-            let origin = TypeVariableOrigin { param_def_id: None, span };
             // Make `Self` be equivalent to the type of the call chain
             // expression we're looking at now, so that we can tell what
             // for example `Iterator::Item` is at this point in the chain.
@@ -4277,11 +4272,11 @@
             // This will hold the resolved type of the associated type, if the
             // current expression implements the trait that associated type is
             // in. For example, this would be what `Iterator::Item` is here.
-            let ty = self.infcx.next_ty_var(origin);
+            let ty = self.infcx.next_ty_var(span);
             // This corresponds to `<ExprTy as Iterator>::Item = _`.
             let projection = ty::Binder::dummy(ty::PredicateKind::Clause(
                 ty::ClauseKind::Projection(ty::ProjectionPredicate {
-                    projection_ty: ty::AliasTy::new(self.tcx, proj.def_id, args),
+                    projection_term: ty::AliasTerm::new(self.tcx, proj.def_id, args),
                     term: ty.into(),
                 }),
             ));
@@ -4323,8 +4318,8 @@
     ) {
         // We can only suggest the slice coersion for function and binary operation arguments,
         // since the suggestion would make no sense in turbofish or call
-        let (ObligationCauseCode::BinOp { .. }
-        | ObligationCauseCode::FunctionArgumentObligation { .. }) = obligation.cause.code()
+        let (ObligationCauseCode::BinOp { .. } | ObligationCauseCode::FunctionArg { .. }) =
+            obligation.cause.code()
         else {
             return;
         };
@@ -4410,7 +4405,7 @@
                     return;
                 }
 
-                if let ObligationCauseCode::FunctionArgumentObligation {
+                if let ObligationCauseCode::FunctionArg {
                     call_hir_id,
                     arg_hir_id,
                     parent_code: _,
@@ -4970,7 +4965,7 @@
     trait_name: &str,
     predicate: ty::Predicate<'_>,
     generics: &hir::Generics<'_>,
-    data: &ImplDerivedObligationCause<'_>,
+    data: &ImplDerivedCause<'_>,
 ) {
     let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() else {
         return;
@@ -4978,7 +4973,7 @@
     let ty::ClauseKind::Projection(proj) = clause else {
         return;
     };
-    let name = tcx.item_name(proj.projection_ty.def_id);
+    let name = tcx.item_name(proj.projection_term.def_id);
     let mut predicates = generics.predicates.iter().peekable();
     let mut prev: Option<&hir::WhereBoundPredicate<'_>> = None;
     while let Some(pred) = predicates.next() {
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index e50cb2a..494fca0 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -6,7 +6,6 @@
     AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch,
 };
 use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
-use crate::infer::type_variable::TypeVariableOrigin;
 use crate::infer::InferCtxtExt as _;
 use crate::infer::{self, InferCtxt};
 use crate::traits::error_reporting::infer_ctxt_ext::InferCtxtExt;
@@ -38,11 +37,15 @@
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
 use rustc_middle::ty::fold::{BottomUpFolder, TypeFolder, TypeSuperFoldable};
-use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
-use rustc_middle::ty::{
-    self, SubtypePredicate, ToPolyTraitRef, ToPredicate, TraitRef, Ty, TyCtxt, TypeFoldable,
-    TypeVisitable, TypeVisitableExt,
+use rustc_middle::ty::print::{
+    with_forced_trimmed_paths, FmtPrinter, Print, PrintTraitPredicateExt as _,
+    PrintTraitRefExt as _,
 };
+use rustc_middle::ty::{
+    self, SubtypePredicate, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitable,
+    TypeVisitableExt, Upcast,
+};
+use rustc_middle::{bug, span_bug};
 use rustc_session::config::DumpSolverProofTree;
 use rustc_session::Limit;
 use rustc_span::def_id::LOCAL_CRATE;
@@ -60,7 +63,7 @@
 pub use rustc_infer::traits::error_reporting::*;
 
 pub enum OverflowCause<'tcx> {
-    DeeplyNormalize(ty::AliasTy<'tcx>),
+    DeeplyNormalize(ty::AliasTerm<'tcx>),
     TraitSolver(ty::Predicate<'tcx>),
 }
 
@@ -244,10 +247,10 @@
         }
 
         let mut err = match cause {
-            OverflowCause::DeeplyNormalize(alias_ty) => {
-                let alias_ty = self.resolve_vars_if_possible(alias_ty);
-                let kind = alias_ty.opt_kind(self.tcx).map_or("alias", |k| k.descr());
-                let alias_str = with_short_path(self.tcx, alias_ty);
+            OverflowCause::DeeplyNormalize(alias_term) => {
+                let alias_term = self.resolve_vars_if_possible(alias_term);
+                let kind = alias_term.kind(self.tcx).descr();
+                let alias_str = with_short_path(self.tcx, alias_term);
                 struct_span_code_err!(
                     self.dcx(),
                     span,
@@ -299,9 +302,9 @@
         suggest_increasing_limit: bool,
     ) -> !
     where
-        T: ToPredicate<'tcx> + Clone,
+        T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + Clone,
     {
-        let predicate = obligation.predicate.clone().to_predicate(self.tcx);
+        let predicate = obligation.predicate.clone().upcast(self.tcx);
         let predicate = self.resolve_vars_if_possible(predicate);
         self.report_overflow_error(
             OverflowCause::TraitSolver(predicate),
@@ -392,7 +395,7 @@
                     }
                 }
 
-                if let ObligationCauseCode::CompareImplItemObligation {
+                if let ObligationCauseCode::CompareImplItem {
                     impl_item_def_id,
                     trait_item_def_id,
                     kind: _,
@@ -419,6 +422,7 @@
                     ty::PredicateKind::Clause(ty::ClauseKind::Trait(trait_predicate)) => {
                         let trait_predicate = bound_predicate.rebind(trait_predicate);
                         let trait_predicate = self.resolve_vars_if_possible(trait_predicate);
+                        let trait_predicate = self.apply_do_not_recommend(trait_predicate, &mut obligation);
 
                         // Let's use the root obligation as the main message, when we care about the
                         // most general case ("X doesn't implement Pattern<'_>") over the case that
@@ -1000,6 +1004,34 @@
         err.emit()
     }
 
+    fn apply_do_not_recommend(
+        &self,
+        mut trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+        obligation: &'_ mut PredicateObligation<'tcx>,
+    ) -> ty::Binder<'tcx, ty::TraitPredicate<'tcx>> {
+        let mut base_cause = obligation.cause.code().clone();
+        loop {
+            if let ObligationCauseCode::ImplDerived(ref c) = base_cause {
+                if self.tcx.has_attrs_with_path(
+                    c.impl_or_alias_def_id,
+                    &[sym::diagnostic, sym::do_not_recommend],
+                ) {
+                    let code = (*c.derived.parent_code).clone();
+                    obligation.cause.map_code(|_| code);
+                    obligation.predicate = c.derived.parent_trait_pred.upcast(self.tcx);
+                    trait_predicate = c.derived.parent_trait_pred.clone();
+                }
+            }
+            if let Some((parent_cause, _parent_pred)) = base_cause.parent() {
+                base_cause = parent_cause.clone();
+            } else {
+                break;
+            }
+        }
+
+        trait_predicate
+    }
+
     fn emit_specialized_closure_kind_error(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -1018,7 +1050,7 @@
             if let Some((_, Some(parent))) = obligation.cause.code().parent() {
                 // If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
                 trait_ref = parent.to_poly_trait_ref();
-            } else if let &ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
+            } else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } =
                 obligation.cause.code()
                 && let Some(typeck_results) = &self.typeck_results
                 && let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) =
@@ -1105,8 +1137,7 @@
         &self,
         obligation: &PredicateObligation<'tcx>,
     ) -> Result<(), ErrorGuaranteed> {
-        if let ObligationCauseCode::FunctionArgumentObligation { arg_hir_id, .. } =
-            obligation.cause.code()
+        if let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()
             && let Node::Expr(arg) = self.tcx.hir_node(*arg_hir_id)
             && let arg = arg.peel_borrows()
             && let hir::ExprKind::Path(hir::QPath::Resolved(
@@ -1415,7 +1446,7 @@
         };
 
         let mut code = obligation.cause.code();
-        let mut pred = obligation.predicate.to_opt_poly_trait_pred();
+        let mut pred = obligation.predicate.as_trait_clause();
         while let Some((next_code, next_pred)) = code.parent() {
             if let Some(pred) = pred {
                 self.enter_forall(pred, |pred| {
@@ -1467,7 +1498,7 @@
         );
 
         let param_env = ty::ParamEnv::empty();
-        self.can_eq(param_env, goal.projection_ty, assumption.projection_ty)
+        self.can_eq(param_env, goal.projection_term, assumption.projection_term)
             && self.can_eq(param_env, goal.term, assumption.term)
     }
 
@@ -1479,16 +1510,16 @@
             return true;
         }
 
-        if let Some(error) = error.to_opt_poly_trait_pred() {
+        if let Some(error) = error.as_trait_clause() {
             self.enter_forall(error, |error| {
                 elaborate(self.tcx, std::iter::once(cond))
-                    .filter_map(|implied| implied.to_opt_poly_trait_pred())
+                    .filter_map(|implied| implied.as_trait_clause())
                     .any(|implied| self.can_match_trait(error, implied))
             })
-        } else if let Some(error) = error.to_opt_poly_projection_pred() {
+        } else if let Some(error) = error.as_projection_clause() {
             self.enter_forall(error, |error| {
                 elaborate(self.tcx, std::iter::once(cond))
-                    .filter_map(|implied| implied.to_opt_poly_projection_pred())
+                    .filter_map(|implied| implied.as_projection_clause())
                     .any(|implied| self.can_match_projection(error, implied))
             })
         } else {
@@ -1505,13 +1536,12 @@
         }
 
         match error.code {
-            FulfillmentErrorCode::SelectionError(ref selection_error) => self
-                .report_selection_error(
-                    error.obligation.clone(),
-                    &error.root_obligation,
-                    selection_error,
-                ),
-            FulfillmentErrorCode::ProjectionError(ref e) => {
+            FulfillmentErrorCode::Select(ref selection_error) => self.report_selection_error(
+                error.obligation.clone(),
+                &error.root_obligation,
+                selection_error,
+            ),
+            FulfillmentErrorCode::Project(ref e) => {
                 self.report_projection_error(&error.obligation, e)
             }
             FulfillmentErrorCode::Ambiguity { overflow: None } => {
@@ -1520,7 +1550,7 @@
             FulfillmentErrorCode::Ambiguity { overflow: Some(suggest_increasing_limit) } => {
                 self.report_overflow_no_abort(error.obligation.clone(), suggest_increasing_limit)
             }
-            FulfillmentErrorCode::SubtypeError(ref expected_found, ref err) => self
+            FulfillmentErrorCode::Subtype(ref expected_found, ref err) => self
                 .report_mismatched_types(
                     &error.obligation.cause,
                     expected_found.expected,
@@ -1528,7 +1558,7 @@
                     *err,
                 )
                 .emit(),
-            FulfillmentErrorCode::ConstEquateError(ref expected_found, ref err) => {
+            FulfillmentErrorCode::ConstEquate(ref expected_found, ref err) => {
                 let mut diag = self.report_mismatched_consts(
                     &error.obligation.cause,
                     expected_found.expected,
@@ -1536,10 +1566,8 @@
                     *err,
                 );
                 let code = error.obligation.cause.code().peel_derives().peel_match_impls();
-                if let ObligationCauseCode::BindingObligation(..)
-                | ObligationCauseCode::ItemObligation(..)
-                | ObligationCauseCode::ExprBindingObligation(..)
-                | ObligationCauseCode::ExprItemObligation(..) = code
+                if let ObligationCauseCode::WhereClause(..)
+                | ObligationCauseCode::WhereClauseInExpr(..) = code
                 {
                     self.note_obligation_cause_code(
                         error.obligation.cause.body_id,
@@ -1585,23 +1613,7 @@
                     infer::BoundRegionConversionTime::HigherRankedType,
                     bound_predicate.rebind(data),
                 );
-                let unnormalized_term = match data.term.unpack() {
-                    ty::TermKind::Ty(_) => Ty::new_projection(
-                        self.tcx,
-                        data.projection_ty.def_id,
-                        data.projection_ty.args,
-                    )
-                    .into(),
-                    ty::TermKind::Const(ct) => ty::Const::new_unevaluated(
-                        self.tcx,
-                        ty::UnevaluatedConst {
-                            def: data.projection_ty.def_id,
-                            args: data.projection_ty.args,
-                        },
-                        ct.ty(),
-                    )
-                    .into(),
-                };
+                let unnormalized_term = data.projection_term.to_term(self.tcx);
                 // FIXME(-Znext-solver): For diagnostic purposes, it would be nice
                 // to deeply normalize this type.
                 let normalized_term =
@@ -1613,11 +1625,9 @@
 
                 let is_normalized_term_expected = !matches!(
                     obligation.cause.code().peel_derives(),
-                    ObligationCauseCode::ItemObligation(_)
-                        | ObligationCauseCode::BindingObligation(_, _)
-                        | ObligationCauseCode::ExprItemObligation(..)
-                        | ObligationCauseCode::ExprBindingObligation(..)
-                        | ObligationCauseCode::Coercion { .. }
+                    |ObligationCauseCode::WhereClause(..)| ObligationCauseCode::WhereClauseInExpr(
+                        ..
+                    ) | ObligationCauseCode::Coercion { .. }
                 );
 
                 let (expected, actual) = if is_normalized_term_expected {
@@ -1668,13 +1678,13 @@
                     return None;
                 };
 
-                let trait_assoc_item = self.tcx.opt_associated_item(proj.projection_ty.def_id)?;
+                let trait_assoc_item = self.tcx.opt_associated_item(proj.projection_term.def_id)?;
                 let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
 
                 let mut associated_items = vec![];
                 self.tcx.for_each_relevant_impl(
-                    self.tcx.trait_of_item(proj.projection_ty.def_id)?,
-                    proj.projection_ty.self_ty(),
+                    self.tcx.trait_of_item(proj.projection_term.def_id)?,
+                    proj.projection_term.self_ty(),
                     |impl_def_id| {
                         associated_items.extend(
                             self.tcx
@@ -1743,11 +1753,11 @@
         normalized_ty: ty::Term<'tcx>,
         expected_ty: ty::Term<'tcx>,
     ) -> Option<String> {
-        let trait_def_id = pred.projection_ty.trait_def_id(self.tcx);
-        let self_ty = pred.projection_ty.self_ty();
+        let trait_def_id = pred.projection_term.trait_def_id(self.tcx);
+        let self_ty = pred.projection_term.self_ty();
 
         with_forced_trimmed_paths! {
-            if Some(pred.projection_ty.def_id) == self.tcx.lang_items().fn_once_output() {
+            if Some(pred.projection_term.def_id) == self.tcx.lang_items().fn_once_output() {
                 let fn_kind = self_ty.prefix_string(self.tcx);
                 let item = match self_ty.kind() {
                     ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(),
@@ -2213,7 +2223,7 @@
         code: &ObligationCauseCode<'tcx>,
     ) -> Option<(Ty<'tcx>, Option<Span>)> {
         match code {
-            ObligationCauseCode::BuiltinDerivedObligation(data) => {
+            ObligationCauseCode::BuiltinDerived(data) => {
                 let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
                 match self.get_parent_trait_ref(&data.parent_code) {
                     Some(t) => Some(t),
@@ -2225,7 +2235,7 @@
                     }
                 }
             }
-            ObligationCauseCode::FunctionArgumentObligation { parent_code, .. } => {
+            ObligationCauseCode::FunctionArg { parent_code, .. } => {
                 self.get_parent_trait_ref(parent_code)
             }
             _ => None,
@@ -2434,8 +2444,8 @@
                         return e;
                     }
                     err.note(format!("cannot satisfy `{predicate}`"));
-                    let impl_candidates = self
-                        .find_similar_impl_candidates(predicate.to_opt_poly_trait_pred().unwrap());
+                    let impl_candidates =
+                        self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap());
                     if impl_candidates.len() < 40 {
                         self.report_similar_impl_candidates(
                             impl_candidates.as_slice(),
@@ -2448,8 +2458,8 @@
                     }
                 }
 
-                if let ObligationCauseCode::ItemObligation(def_id)
-                | ObligationCauseCode::ExprItemObligation(def_id, ..) = *obligation.cause.code()
+                if let ObligationCauseCode::WhereClause(def_id, _)
+                | ObligationCauseCode::WhereClauseInExpr(def_id, ..) = *obligation.cause.code()
                 {
                     self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
                 }
@@ -2626,14 +2636,14 @@
                 }
 
                 if let Err(guar) =
-                    self.tcx.ensure().coherent_trait(self.tcx.parent(data.projection_ty.def_id))
+                    self.tcx.ensure().coherent_trait(self.tcx.parent(data.projection_term.def_id))
                 {
                     // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
                     // other `Foo` impls are incoherent.
                     return guar;
                 }
                 let arg = data
-                    .projection_ty
+                    .projection_term
                     .args
                     .iter()
                     .chain(Some(data.term.into_arg()))
@@ -2826,9 +2836,7 @@
             fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
                 if let ty::Param(_) = *ty.kind() {
                     let infcx = self.infcx;
-                    *self.var_map.entry(ty).or_insert_with(|| {
-                        infcx.next_ty_var(TypeVariableOrigin { param_def_id: None, span: DUMMY_SP })
-                    })
+                    *self.var_map.entry(ty).or_insert_with(|| infcx.next_ty_var(DUMMY_SP))
                 } else {
                     ty.super_fold_with(self)
                 }
@@ -2886,12 +2894,15 @@
         else {
             return;
         };
-        let (ObligationCauseCode::BindingObligation(item_def_id, span)
-        | ObligationCauseCode::ExprBindingObligation(item_def_id, span, ..)) =
+        let (ObligationCauseCode::WhereClause(item_def_id, span)
+        | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)) =
             *obligation.cause.code().peel_derives()
         else {
             return;
         };
+        if span.is_dummy() {
+            return;
+        }
         debug!(?pred, ?item_def_id, ?span);
 
         let (Some(node), true) = (
@@ -3007,7 +3018,7 @@
         obligated_types: &mut Vec<Ty<'tcx>>,
         cause_code: &ObligationCauseCode<'tcx>,
     ) -> bool {
-        if let ObligationCauseCode::BuiltinDerivedObligation(ref data) = cause_code {
+        if let ObligationCauseCode::BuiltinDerived(ref data) = cause_code {
             let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
             let self_ty = parent_trait_ref.skip_binder().self_ty();
             if obligated_types.iter().any(|ot| ot == &self_ty) {
@@ -3184,10 +3195,7 @@
             ObligationCauseCode::RustCall => {
                 err.primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument");
             }
-            ObligationCauseCode::BindingObligation(def_id, _)
-            | ObligationCauseCode::ItemObligation(def_id)
-                if self.tcx.is_fn_trait(*def_id) =>
-            {
+            ObligationCauseCode::WhereClause(def_id, _) if self.tcx.is_fn_trait(*def_id) => {
                 err.code(E0059);
                 err.primary_message(format!(
                     "type parameter to bare `{}` trait must be a tuple",
@@ -3443,8 +3451,6 @@
         self.dcx().try_steal_replace_and_emit_err(self.tcx.def_span(def_id), StashKey::Cycle, err)
     }
 
-    // FIXME(@lcnr): This function could be changed to trait `TraitRef` directly
-    // instead of using a `Binder`.
     fn report_signature_mismatch_error(
         &self,
         obligation: &PredicateObligation<'tcx>,
@@ -3576,7 +3582,7 @@
                     match self.tcx.sess.source_map().span_to_snippet(const_span) {
                         Ok(snippet) => {
                             let code = format!("[(); {snippet}{cast}]:");
-                            let def_id = if let ObligationCauseCode::CompareImplItemObligation {
+                            let def_id = if let ObligationCauseCode::CompareImplItem {
                                 trait_item_def_id,
                                 ..
                             } = obligation.cause.code()
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 1f10cb7..07fcf10 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -8,6 +8,7 @@
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::traits::ProjectionCacheKey;
 use rustc_infer::traits::{PolyTraitObligation, SelectionError, TraitEngine};
+use rustc_middle::bug;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
@@ -411,7 +412,7 @@
 
                 ty::PredicateKind::ObjectSafe(trait_def_id) => {
                     if !self.selcx.tcx().check_is_object_safe(trait_def_id) {
-                        ProcessResult::Error(FulfillmentErrorCode::SelectionError(Unimplemented))
+                        ProcessResult::Error(FulfillmentErrorCode::Select(Unimplemented))
                     } else {
                         ProcessResult::Changed(vec![])
                     }
@@ -435,7 +436,7 @@
                         ty,
                     ) {
                         Ok(inf_ok) => ProcessResult::Changed(mk_pending(inf_ok.into_obligations())),
-                        Err(_) => ProcessResult::Error(FulfillmentErrorCode::SelectionError(
+                        Err(_) => ProcessResult::Error(FulfillmentErrorCode::Select(
                             SelectionError::Unimplemented,
                         )),
                     }
@@ -493,10 +494,7 @@
                         Ok(Err(err)) => {
                             let expected_found =
                                 ExpectedFound::new(subtype.a_is_expected, subtype.a, subtype.b);
-                            ProcessResult::Error(FulfillmentErrorCode::SubtypeError(
-                                expected_found,
-                                err,
-                            ))
+                            ProcessResult::Error(FulfillmentErrorCode::Subtype(expected_found, err))
                         }
                     }
                 }
@@ -516,10 +514,7 @@
                         Ok(Ok(ok)) => ProcessResult::Changed(mk_pending(ok.obligations)),
                         Ok(Err(err)) => {
                             let expected_found = ExpectedFound::new(false, coerce.a, coerce.b);
-                            ProcessResult::Error(FulfillmentErrorCode::SubtypeError(
-                                expected_found,
-                                err,
-                            ))
+                            ProcessResult::Error(FulfillmentErrorCode::Subtype(expected_found, err))
                         }
                     }
                 }
@@ -542,7 +537,7 @@
                         Err(
                             e @ NotConstEvaluatable::MentionsParam
                             | e @ NotConstEvaluatable::Error(_),
-                        ) => ProcessResult::Error(FulfillmentErrorCode::SelectionError(
+                        ) => ProcessResult::Error(FulfillmentErrorCode::Select(
                             SelectionError::NotConstEvaluatable(e),
                         )),
                     }
@@ -638,7 +633,7 @@
                                     ProcessResult::Changed(mk_pending(inf_ok.into_obligations()))
                                 }
                                 Err(err) => {
-                                    ProcessResult::Error(FulfillmentErrorCode::ConstEquateError(
+                                    ProcessResult::Error(FulfillmentErrorCode::ConstEquate(
                                         ExpectedFound::new(true, c1, c2),
                                         err,
                                     ))
@@ -646,13 +641,11 @@
                             }
                         }
                         (Err(ErrorHandled::Reported(reported, _)), _)
-                        | (_, Err(ErrorHandled::Reported(reported, _))) => {
-                            ProcessResult::Error(FulfillmentErrorCode::SelectionError(
-                                SelectionError::NotConstEvaluatable(NotConstEvaluatable::Error(
-                                    reported.into(),
-                                )),
-                            ))
-                        }
+                        | (_, Err(ErrorHandled::Reported(reported, _))) => ProcessResult::Error(
+                            FulfillmentErrorCode::Select(SelectionError::NotConstEvaluatable(
+                                NotConstEvaluatable::Error(reported.into()),
+                            )),
+                        ),
                         (Err(ErrorHandled::TooGeneric(_)), _)
                         | (_, Err(ErrorHandled::TooGeneric(_))) => {
                             if c1.has_non_region_infer() || c2.has_non_region_infer() {
@@ -660,7 +653,7 @@
                             } else {
                                 // Two different constants using generic parameters ~> error.
                                 let expected_found = ExpectedFound::new(true, c1, c2);
-                                ProcessResult::Error(FulfillmentErrorCode::ConstEquateError(
+                                ProcessResult::Error(FulfillmentErrorCode::ConstEquate(
                                     expected_found,
                                     TypeError::ConstMismatch(expected_found),
                                 ))
@@ -741,7 +734,7 @@
             Err(selection_err) => {
                 debug!("selecting trait at depth {} yielded Err", obligation.recursion_depth);
 
-                ProcessResult::Error(FulfillmentErrorCode::SelectionError(selection_err))
+                ProcessResult::Error(FulfillmentErrorCode::Select(selection_err))
             }
         }
     }
@@ -778,13 +771,13 @@
             }
         }
 
-        match project::poly_project_and_unify_type(&mut self.selcx, &project_obligation) {
+        match project::poly_project_and_unify_term(&mut self.selcx, &project_obligation) {
             ProjectAndUnifyResult::Holds(os) => ProcessResult::Changed(mk_pending(os)),
             ProjectAndUnifyResult::FailedNormalization => {
                 stalled_on.clear();
                 stalled_on.extend(args_infer_vars(
                     &self.selcx,
-                    project_obligation.predicate.map_bound(|pred| pred.projection_ty.args),
+                    project_obligation.predicate.map_bound(|pred| pred.projection_term.args),
                 ));
                 ProcessResult::Unchanged
             }
@@ -793,7 +786,7 @@
                 project_obligation.with(tcx, project_obligation.predicate),
             ])),
             ProjectAndUnifyResult::MismatchedProjectionTypes(e) => {
-                ProcessResult::Error(FulfillmentErrorCode::ProjectionError(e))
+                ProcessResult::Error(FulfillmentErrorCode::Project(e))
             }
         }
     }
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index 93f9c23..da2b004 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -10,7 +10,7 @@
 use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
 use rustc_infer::traits::query::NoSolution;
 use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError};
-use rustc_middle::ty::{self, AdtDef, GenericArg, List, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::DUMMY_SP;
 
 use super::outlives_bounds::InferCtxtExt;
@@ -129,7 +129,7 @@
     param_env: ty::ParamEnv<'tcx>,
     self_type: Ty<'tcx>,
     adt: AdtDef<'tcx>,
-    args: &'tcx List<GenericArg<'tcx>>,
+    args: ty::GenericArgsRef<'tcx>,
     parent_cause: ObligationCause<'tcx>,
     lang_item: LangItem,
 ) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> {
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 56f8b4b..204bb48 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -31,9 +31,10 @@
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_errors::ErrorGuaranteed;
 use rustc_middle::query::Providers;
+use rustc_middle::span_bug;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFolder, TypeSuperVisitable};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeFolder, TypeSuperVisitable, Upcast};
 use rustc_middle::ty::{GenericArgs, GenericArgsRef};
 use rustc_span::def_id::DefId;
 use rustc_span::Span;
@@ -51,7 +52,7 @@
 pub use self::object_safety::is_vtable_safe_method;
 pub use self::object_safety::object_safety_violations_for_assoc_item;
 pub use self::object_safety::ObjectSafetyViolation;
-pub use self::project::{normalize_inherent_projection, normalize_projection_type};
+pub use self::project::{normalize_inherent_projection, normalize_projection_ty};
 pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
 pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
 pub use self::specialize::specialization_graph::FutureCompatOverlapError;
@@ -141,7 +142,7 @@
 fn pred_known_to_hold_modulo_regions<'tcx>(
     infcx: &InferCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    pred: impl ToPredicate<'tcx>,
+    pred: impl Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>>,
 ) -> bool {
     let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred);
 
@@ -456,7 +457,7 @@
     // associated items.
     if let Some(trait_def_id) = tcx.trait_of_item(key.0) {
         let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, key.1);
-        predicates.push(ty::Binder::dummy(trait_ref).to_predicate(tcx));
+        predicates.push(trait_ref.upcast(tcx));
     }
 
     predicates.retain(|predicate| !predicate.has_param());
diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs
index 43f4fa8..d10aee2 100644
--- a/compiler/rustc_trait_selection/src/traits/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/normalize.rs
@@ -213,7 +213,7 @@
                         let recursion_limit = self.interner().recursion_limit();
                         if !recursion_limit.value_within_limit(self.depth) {
                             self.selcx.infcx.err_ctxt().report_overflow_error(
-                                OverflowCause::DeeplyNormalize(data),
+                                OverflowCause::DeeplyNormalize(data.into()),
                                 self.cause.span,
                                 true,
                                 |_| {},
@@ -238,7 +238,7 @@
                 // register an obligation to *later* project, since we know
                 // there won't be bound vars there.
                 let data = data.fold_with(self);
-                let normalized_ty = project::normalize_projection_type(
+                let normalized_ty = project::normalize_projection_ty(
                     self.selcx,
                     self.param_env,
                     data,
@@ -273,10 +273,10 @@
                 let (data, mapped_regions, mapped_types, mapped_consts) =
                     BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
                 let data = data.fold_with(self);
-                let normalized_ty = project::opt_normalize_projection_type(
+                let normalized_ty = project::opt_normalize_projection_term(
                     self.selcx,
                     self.param_env,
-                    data,
+                    data.into(),
                     self.cause.clone(),
                     self.depth,
                     self.obligations,
@@ -309,7 +309,7 @@
                 let recursion_limit = self.interner().recursion_limit();
                 if !recursion_limit.value_within_limit(self.depth) {
                     self.selcx.infcx.err_ctxt().report_overflow_error(
-                        OverflowCause::DeeplyNormalize(data),
+                        OverflowCause::DeeplyNormalize(data.into()),
                         self.cause.span,
                         false,
                         |diag| {
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index 0e15dd2..8ce1271 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -18,10 +18,11 @@
 use rustc_hir::def_id::DefId;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{
-    self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
+    self, EarlyBinder, ExistentialPredicateStableCmpExt as _, Ty, TyCtxt, TypeSuperVisitable,
+    TypeVisitable, TypeVisitor,
 };
 use rustc_middle::ty::{GenericArg, GenericArgs};
-use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
+use rustc_middle::ty::{TypeVisitableExt, Upcast};
 use rustc_session::lint::builtin::WHERE_CLAUSES_OBJECT_SAFETY;
 use rustc_span::symbol::Symbol;
 use rustc_span::Span;
@@ -304,7 +305,7 @@
             //
             // This is ALT2 in issue #56288, see that for discussion of the
             // possible alternatives.
-            data.projection_ty.args[1..].iter().any(has_self_ty).then_some(sp)
+            data.projection_term.args[1..].iter().any(has_self_ty).then_some(sp)
         }
         ty::ClauseKind::ConstArgHasType(_ct, ty) => has_self_ty(&ty.into()).then_some(sp),
 
@@ -397,7 +398,7 @@
         // Associated types can only be object safe if they have `Self: Sized` bounds.
         ty::AssocKind::Type => {
             if !tcx.features().generic_associated_types_extended
-                && !tcx.generics_of(item.def_id).params.is_empty()
+                && !tcx.generics_of(item.def_id).is_own_empty()
                 && !item.is_impl_trait_in_trait()
             {
                 vec![ObjectSafetyViolation::GAT(item.name, item.ident(tcx).span)]
@@ -648,11 +649,11 @@
     ));
     debug!(?trait_predicate);
 
-    let pred: ty::Predicate<'tcx> = trait_ref.to_predicate(tcx);
+    let pred: ty::Predicate<'tcx> = trait_ref.upcast(tcx);
     let mut elaborated_predicates: Vec<_> = elaborate(tcx, [pred])
         .filter_map(|pred| {
             debug!(?pred);
-            let pred = pred.to_opt_poly_projection_pred()?;
+            let pred = pred.as_projection_clause()?;
             Some(pred.map_bound(|p| {
                 ty::ExistentialPredicate::Projection(ty::ExistentialProjection::erase_self_ty(
                     tcx, p,
@@ -751,8 +752,7 @@
 
         // Self: Unsize<U>
         let unsize_predicate =
-            ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty])
-                .to_predicate(tcx);
+            ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty]).upcast(tcx);
 
         // U: Trait<Arg1, ..., ArgN>
         let trait_predicate = {
@@ -761,7 +761,7 @@
                 if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
             });
 
-            ty::TraitRef::new(tcx, trait_def_id, args).to_predicate(tcx)
+            ty::TraitRef::new(tcx, trait_def_id, args).upcast(tcx)
         };
 
         let caller_bounds =
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index 1dd2ada..1dc2ebf 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -5,6 +5,7 @@
 use rustc_infer::infer::InferOk;
 use rustc_macros::extension;
 use rustc_middle::infer::canonical::{OriginalQueryValues, QueryRegionConstraints};
+use rustc_middle::span_bug;
 use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt};
 use rustc_span::def_id::LocalDefId;
 
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 116e17c..77ac4be 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -12,13 +12,14 @@
 use super::Selection;
 use super::SelectionContext;
 use super::SelectionError;
-use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
+use super::{Normalized, NormalizedTerm, ProjectionCacheEntry, ProjectionCacheKey};
+use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::traits::ImplSource;
 use rustc_middle::traits::ImplSourceUserDefinedData;
+use rustc_middle::{bug, span_bug};
 
 use crate::errors::InherentProjectionNormalizationOverflow;
-use crate::infer::type_variable::TypeVariableOrigin;
 use crate::infer::{BoundRegionConversionTime, InferOk};
 use crate::traits::normalize::normalize_with_depth;
 use crate::traits::normalize::normalize_with_depth_to;
@@ -34,7 +35,7 @@
 use rustc_middle::traits::select::OverflowError;
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::visit::{MaxUniverse, TypeVisitable, TypeVisitableExt};
-use rustc_middle::ty::{self, Term, ToPredicate, Ty, TyCtxt};
+use rustc_middle::ty::{self, Term, Ty, TyCtxt, Upcast};
 use rustc_span::symbol::sym;
 
 pub use rustc_middle::traits::Reveal;
@@ -43,7 +44,7 @@
 
 pub type ProjectionObligation<'tcx> = Obligation<'tcx, ty::ProjectionPredicate<'tcx>>;
 
-pub type ProjectionTyObligation<'tcx> = Obligation<'tcx, ty::AliasTy<'tcx>>;
+pub type ProjectionTermObligation<'tcx> = Obligation<'tcx, ty::AliasTerm<'tcx>>;
 
 pub(super) struct InProgress;
 
@@ -181,7 +182,7 @@
 /// If successful, this may result in additional obligations. Also returns
 /// the projection cache key used to track these additional obligations.
 #[instrument(level = "debug", skip(selcx))]
-pub(super) fn poly_project_and_unify_type<'cx, 'tcx>(
+pub(super) fn poly_project_and_unify_term<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &PolyProjectionObligation<'tcx>,
 ) -> ProjectAndUnifyResult<'tcx> {
@@ -192,7 +193,7 @@
         let new_universe = infcx.universe();
 
         let placeholder_obligation = obligation.with(infcx.tcx, placeholder_predicate);
-        match project_and_unify_type(selcx, &placeholder_obligation) {
+        match project_and_unify_term(selcx, &placeholder_obligation) {
             ProjectAndUnifyResult::MismatchedProjectionTypes(e) => Err(e),
             ProjectAndUnifyResult::Holds(obligations)
                 if old_universe != new_universe
@@ -232,19 +233,19 @@
 /// ```
 /// If successful, this may result in additional obligations.
 ///
-/// See [poly_project_and_unify_type] for an explanation of the return value.
+/// See [poly_project_and_unify_term] for an explanation of the return value.
 #[instrument(level = "debug", skip(selcx))]
-fn project_and_unify_type<'cx, 'tcx>(
+fn project_and_unify_term<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
     obligation: &ProjectionObligation<'tcx>,
 ) -> ProjectAndUnifyResult<'tcx> {
     let mut obligations = vec![];
 
     let infcx = selcx.infcx;
-    let normalized = match opt_normalize_projection_type(
+    let normalized = match opt_normalize_projection_term(
         selcx,
         obligation.param_env,
-        obligation.predicate.projection_ty,
+        obligation.predicate.projection_term,
         obligation.cause.clone(),
         obligation.recursion_depth,
         &mut obligations,
@@ -290,7 +291,7 @@
 /// there are unresolved type variables in the projection, we will
 /// instantiate it with a fresh type variable `$X` and generate a new
 /// obligation `<T as Trait>::Item == $X` for later.
-pub fn normalize_projection_type<'a, 'b, 'tcx>(
+pub fn normalize_projection_ty<'a, 'b, 'tcx>(
     selcx: &'a mut SelectionContext<'b, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     projection_ty: ty::AliasTy<'tcx>,
@@ -298,10 +299,10 @@
     depth: usize,
     obligations: &mut Vec<PredicateObligation<'tcx>>,
 ) -> Term<'tcx> {
-    opt_normalize_projection_type(
+    opt_normalize_projection_term(
         selcx,
         param_env,
-        projection_ty,
+        projection_ty.into(),
         cause.clone(),
         depth,
         obligations,
@@ -313,7 +314,10 @@
         // and a deferred predicate to resolve this when more type
         // information is available.
 
-        selcx.infcx.infer_projection(param_env, projection_ty, cause, depth + 1, obligations).into()
+        selcx
+            .infcx
+            .projection_ty_to_infer(param_env, projection_ty, cause, depth + 1, obligations)
+            .into()
     })
 }
 
@@ -328,10 +332,10 @@
 /// function takes an obligations vector and appends to it directly, which is
 /// slightly uglier but avoids the need for an extra short-lived allocation.
 #[instrument(level = "debug", skip(selcx, param_env, cause, obligations))]
-pub(super) fn opt_normalize_projection_type<'a, 'b, 'tcx>(
+pub(super) fn opt_normalize_projection_term<'a, 'b, 'tcx>(
     selcx: &'a mut SelectionContext<'b, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    projection_ty: ty::AliasTy<'tcx>,
+    projection_term: ty::AliasTerm<'tcx>,
     cause: ObligationCause<'tcx>,
     depth: usize,
     obligations: &mut Vec<PredicateObligation<'tcx>>,
@@ -343,8 +347,8 @@
     // mode, which could lead to using incorrect cache results.
     let use_cache = !selcx.is_intercrate();
 
-    let projection_ty = infcx.resolve_vars_if_possible(projection_ty);
-    let cache_key = ProjectionCacheKey::new(projection_ty, param_env);
+    let projection_term = infcx.resolve_vars_if_possible(projection_term);
+    let cache_key = ProjectionCacheKey::new(projection_term, param_env);
 
     // FIXME(#20304) For now, I am caching here, which is good, but it
     // means we don't capture the type variables that are created in
@@ -392,7 +396,7 @@
             debug!("recur cache");
             return Err(InProgress);
         }
-        Err(ProjectionCacheEntry::NormalizedTy { ty, complete: _ }) => {
+        Err(ProjectionCacheEntry::NormalizedTerm { ty, complete: _ }) => {
             // This is the hottest path in this function.
             //
             // If we find the value in the cache, then return it along
@@ -410,14 +414,14 @@
         }
         Err(ProjectionCacheEntry::Error) => {
             debug!("opt_normalize_projection_type: found error");
-            let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
+            let result = normalize_to_error(selcx, param_env, projection_term, cause, depth);
             obligations.extend(result.obligations);
             return Ok(Some(result.value.into()));
         }
     }
 
     let obligation =
-        Obligation::with_depth(selcx.tcx(), cause.clone(), depth, param_env, projection_ty);
+        Obligation::with_depth(selcx.tcx(), cause.clone(), depth, param_env, projection_term);
 
     match project(selcx, &obligation) {
         Ok(Projected::Progress(Progress {
@@ -480,7 +484,7 @@
             if use_cache {
                 infcx.inner.borrow_mut().projection_cache().error(cache_key);
             }
-            let result = normalize_to_error(selcx, param_env, projection_ty, cause, depth);
+            let result = normalize_to_error(selcx, param_env, projection_term, cause, depth);
             obligations.extend(result.obligations);
             Ok(Some(result.value.into()))
         }
@@ -509,22 +513,33 @@
 fn normalize_to_error<'a, 'tcx>(
     selcx: &SelectionContext<'a, 'tcx>,
     param_env: ty::ParamEnv<'tcx>,
-    projection_ty: ty::AliasTy<'tcx>,
+    projection_term: ty::AliasTerm<'tcx>,
     cause: ObligationCause<'tcx>,
     depth: usize,
-) -> NormalizedTy<'tcx> {
-    let trait_ref = ty::Binder::dummy(projection_ty.trait_ref(selcx.tcx()));
+) -> NormalizedTerm<'tcx> {
+    let trait_ref = ty::Binder::dummy(projection_term.trait_ref(selcx.tcx()));
+    let new_value = match projection_term.kind(selcx.tcx()) {
+        ty::AliasTermKind::ProjectionTy
+        | ty::AliasTermKind::InherentTy
+        | ty::AliasTermKind::OpaqueTy
+        | ty::AliasTermKind::WeakTy => selcx.infcx.next_ty_var(cause.span).into(),
+        ty::AliasTermKind::UnevaluatedConst | ty::AliasTermKind::ProjectionConst => selcx
+            .infcx
+            .next_const_var(
+                selcx
+                    .tcx()
+                    .type_of(projection_term.def_id)
+                    .instantiate(selcx.tcx(), projection_term.args),
+                cause.span,
+            )
+            .into(),
+    };
     let trait_obligation = Obligation {
         cause,
         recursion_depth: depth,
         param_env,
-        predicate: trait_ref.to_predicate(selcx.tcx()),
+        predicate: trait_ref.upcast(selcx.tcx()),
     };
-    let tcx = selcx.infcx.tcx;
-    let new_value = selcx.infcx.next_ty_var(TypeVariableOrigin {
-        param_def_id: None,
-        span: tcx.def_span(projection_ty.def_id),
-    });
     Normalized { value: new_value, obligations: vec![trait_obligation] }
 }
 
@@ -576,11 +591,7 @@
             // cause code, inherent projections will be printed with identity instantiation in
             // diagnostics which is not ideal.
             // Consider creating separate cause codes for this specific situation.
-            if span.is_dummy() {
-                super::ItemObligation(alias_ty.def_id)
-            } else {
-                super::BindingObligation(alias_ty.def_id, span)
-            },
+            ObligationCauseCode::WhereClause(alias_ty.def_id, span),
         );
 
         obligations.push(Obligation::with_depth(
@@ -682,7 +693,7 @@
 #[instrument(level = "info", skip(selcx))]
 fn project<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
 ) -> Result<Projected<'tcx>, ProjectionError<'tcx>> {
     if !selcx.tcx().recursion_limit().value_within_limit(obligation.recursion_depth) {
         // This should really be an immediate error, but some existing code
@@ -757,7 +768,7 @@
 /// there that can answer this question.
 fn assemble_candidates_from_param_env<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     candidate_set: &mut ProjectionCandidateSet<'tcx>,
 ) {
     assemble_candidates_from_predicates(
@@ -782,7 +793,7 @@
 /// Here, for example, we could conclude that the result is `i32`.
 fn assemble_candidates_from_trait_def<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     candidate_set: &mut ProjectionCandidateSet<'tcx>,
 ) {
     debug!("assemble_candidates_from_trait_def(..)");
@@ -840,7 +851,7 @@
 /// `dyn Iterator<Item = ()>: Iterator` again.
 fn assemble_candidates_from_object_ty<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     candidate_set: &mut ProjectionCandidateSet<'tcx>,
 ) {
     debug!("assemble_candidates_from_object_ty(..)");
@@ -866,7 +877,7 @@
     let env_predicates = data
         .projection_bounds()
         .filter(|bound| bound.item_def_id() == obligation.predicate.def_id)
-        .map(|p| p.with_self_ty(tcx, object_ty).to_predicate(tcx));
+        .map(|p| p.with_self_ty(tcx, object_ty).upcast(tcx));
 
     assemble_candidates_from_predicates(
         selcx,
@@ -884,7 +895,7 @@
 )]
 fn assemble_candidates_from_predicates<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     candidate_set: &mut ProjectionCandidateSet<'tcx>,
     ctor: fn(ty::PolyProjectionPredicate<'tcx>) -> ProjectionCandidate<'tcx>,
     env_predicates: impl Iterator<Item = ty::Clause<'tcx>>,
@@ -932,7 +943,7 @@
 #[instrument(level = "debug", skip(selcx, obligation, candidate_set))]
 fn assemble_candidates_from_impls<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     candidate_set: &mut ProjectionCandidateSet<'tcx>,
 ) {
     // If we are resolving `<T as TraitRef<...>>::Item == Type`,
@@ -977,9 +988,12 @@
                 //
                 // NOTE: This should be kept in sync with the similar code in
                 // `rustc_ty_utils::instance::resolve_associated_item()`.
-                let node_item =
-                    specialization_graph::assoc_def(selcx.tcx(), impl_data.impl_def_id, obligation.predicate.def_id)
-                        .map_err(|ErrorGuaranteed { .. }| ())?;
+                let node_item = specialization_graph::assoc_def(
+                    selcx.tcx(),
+                    impl_data.impl_def_id,
+                    obligation.predicate.def_id,
+                )
+                .map_err(|ErrorGuaranteed { .. }| ())?;
 
                 if node_item.is_final() {
                     // Non-specializable items are always projectable.
@@ -1022,7 +1036,8 @@
                     lang_items.async_fn_trait(),
                     lang_items.async_fn_mut_trait(),
                     lang_items.async_fn_once_trait(),
-                ].contains(&Some(trait_ref.def_id))
+                ]
+                .contains(&Some(trait_ref.def_id))
                 {
                     true
                 } else if lang_items.async_fn_kind_helper() == Some(trait_ref.def_id) {
@@ -1035,7 +1050,7 @@
                         true
                     } else {
                         obligation.predicate.args.type_at(0).to_opt_closure_kind().is_some()
-                        && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some()
+                            && obligation.predicate.args.type_at(1).to_opt_closure_kind().is_some()
                     }
                 } else if lang_items.discriminant_kind_trait() == Some(trait_ref.def_id) {
                     match self_ty.kind() {
@@ -1162,12 +1177,20 @@
                         // Otherwise, type parameters, opaques, and unnormalized projections have
                         // unit metadata if they're known (e.g. by the param_env) to be sized.
                         ty::Param(_) | ty::Alias(..)
-                            if self_ty != tail || selcx.infcx.predicate_must_hold_modulo_regions(
-                                &obligation.with(
-                                    selcx.tcx(),
-                                    ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty]),
-                                ),
-                            ) =>
+                            if self_ty != tail
+                                || selcx.infcx.predicate_must_hold_modulo_regions(
+                                    &obligation.with(
+                                        selcx.tcx(),
+                                        ty::TraitRef::new(
+                                            selcx.tcx(),
+                                            selcx.tcx().require_lang_item(
+                                                LangItem::Sized,
+                                                Some(obligation.cause.span()),
+                                            ),
+                                            [self_ty],
+                                        ),
+                                    ),
+                                ) =>
                         {
                             true
                         }
@@ -1230,7 +1253,7 @@
                     obligation.cause.span,
                     format!("Cannot project an associated type from `{impl_source:?}`"),
                 );
-                return Err(())
+                return Err(());
             }
         };
 
@@ -1248,7 +1271,7 @@
 
 fn confirm_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     candidate: ProjectionCandidate<'tcx>,
 ) -> Progress<'tcx> {
     debug!(?obligation, ?candidate, "confirm_candidate");
@@ -1280,7 +1303,7 @@
 
 fn confirm_select_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     impl_source: Selection<'tcx>,
 ) -> Progress<'tcx> {
     match impl_source {
@@ -1328,7 +1351,7 @@
 
 fn confirm_coroutine_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     nested: Vec<PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
     let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
@@ -1372,7 +1395,7 @@
     };
 
     let predicate = ty::ProjectionPredicate {
-        projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
+        projection_term: ty::AliasTerm::new(tcx, obligation.predicate.def_id, trait_ref.args),
         term: ty.into(),
     };
 
@@ -1383,7 +1406,7 @@
 
 fn confirm_future_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     nested: Vec<PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
     let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
@@ -1416,7 +1439,7 @@
     debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Output);
 
     let predicate = ty::ProjectionPredicate {
-        projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
+        projection_term: ty::AliasTerm::new(tcx, obligation.predicate.def_id, trait_ref.args),
         term: return_ty.into(),
     };
 
@@ -1427,7 +1450,7 @@
 
 fn confirm_iterator_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     nested: Vec<PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
     let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
@@ -1458,7 +1481,7 @@
     debug_assert_eq!(tcx.associated_item(obligation.predicate.def_id).name, sym::Item);
 
     let predicate = ty::ProjectionPredicate {
-        projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
+        projection_term: ty::AliasTerm::new(tcx, obligation.predicate.def_id, trait_ref.args),
         term: yield_ty.into(),
     };
 
@@ -1469,7 +1492,7 @@
 
 fn confirm_async_iterator_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     nested: Vec<PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
     let ty::Coroutine(_, args) = selcx.infcx.shallow_resolve(obligation.predicate.self_ty()).kind()
@@ -1508,7 +1531,7 @@
     let item_ty = args.type_at(0);
 
     let predicate = ty::ProjectionPredicate {
-        projection_ty: ty::AliasTy::new(tcx, obligation.predicate.def_id, trait_ref.args),
+        projection_term: ty::AliasTerm::new(tcx, obligation.predicate.def_id, trait_ref.args),
         term: item_ty.into(),
     };
 
@@ -1519,7 +1542,7 @@
 
 fn confirm_builtin_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     data: Vec<PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
@@ -1559,10 +1582,9 @@
                 // and opaque types: If the `self_ty` is `Sized`, then the metadata is `()`.
                 // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't
                 // exist. Instead, `Pointee<Metadata = ()>` should be a supertrait of `Sized`.
-                let sized_predicate = ty::TraitRef::from_lang_item(
+                let sized_predicate = ty::TraitRef::new(
                     tcx,
-                    LangItem::Sized,
-                    obligation.cause.span(),
+                    tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span())),
                     [self_ty],
                 );
                 obligations.push(obligation.with(tcx, sized_predicate));
@@ -1578,8 +1600,10 @@
         bug!("unexpected builtin trait with associated type: {:?}", obligation.predicate);
     };
 
-    let predicate =
-        ty::ProjectionPredicate { projection_ty: ty::AliasTy::new(tcx, item_def_id, args), term };
+    let predicate = ty::ProjectionPredicate {
+        projection_term: ty::AliasTerm::new(tcx, item_def_id, args),
+        term,
+    };
 
     confirm_param_env_candidate(selcx, obligation, ty::Binder::dummy(predicate), false)
         .with_addl_obligations(obligations)
@@ -1588,7 +1612,7 @@
 
 fn confirm_fn_pointer_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     nested: Vec<PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
@@ -1624,7 +1648,7 @@
 
 fn confirm_closure_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     nested: Vec<PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
@@ -1688,7 +1712,7 @@
                     [sig.tupled_inputs_ty],
                     output_ty,
                     sig.c_variadic,
-                    sig.unsafety,
+                    sig.safety,
                     sig.abi,
                 )
             })
@@ -1723,7 +1747,7 @@
 
 fn confirm_callable_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     fn_sig: ty::PolyFnSig<'tcx>,
     flag: util::TupleArgumentsFlag,
     fn_host_effect: ty::Const<'tcx>,
@@ -1744,7 +1768,7 @@
         fn_host_effect,
     )
     .map_bound(|(trait_ref, ret_type)| ty::ProjectionPredicate {
-        projection_ty: ty::AliasTy::new(tcx, fn_once_output_def_id, trait_ref.args),
+        projection_term: ty::AliasTerm::new(tcx, fn_once_output_def_id, trait_ref.args),
         term: ret_type.into(),
     });
 
@@ -1753,7 +1777,7 @@
 
 fn confirm_async_closure_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     nested: Vec<PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
@@ -1832,13 +1856,13 @@
                 sym::Output => sig.return_ty,
                 name => bug!("no such associated type: {name}"),
             };
-            let projection_ty = match item_name {
-                sym::CallOnceFuture | sym::Output => ty::AliasTy::new(
+            let projection_term = match item_name {
+                sym::CallOnceFuture | sym::Output => ty::AliasTerm::new(
                     tcx,
                     obligation.predicate.def_id,
                     [self_ty, sig.tupled_inputs_ty],
                 ),
-                sym::CallRefFuture => ty::AliasTy::new(
+                sym::CallRefFuture => ty::AliasTerm::new(
                     tcx,
                     obligation.predicate.def_id,
                     [ty::GenericArg::from(self_ty), sig.tupled_inputs_ty.into(), env_region.into()],
@@ -1847,7 +1871,7 @@
             };
 
             args.coroutine_closure_sig()
-                .rebind(ty::ProjectionPredicate { projection_ty, term: term.into() })
+                .rebind(ty::ProjectionPredicate { projection_term, term: term.into() })
         }
         ty::FnDef(..) | ty::FnPtr(..) => {
             let bound_sig = self_ty.fn_sig(tcx);
@@ -1867,13 +1891,13 @@
                 }
                 name => bug!("no such associated type: {name}"),
             };
-            let projection_ty = match item_name {
-                sym::CallOnceFuture | sym::Output => ty::AliasTy::new(
+            let projection_term = match item_name {
+                sym::CallOnceFuture | sym::Output => ty::AliasTerm::new(
                     tcx,
                     obligation.predicate.def_id,
                     [self_ty, Ty::new_tup(tcx, sig.inputs())],
                 ),
-                sym::CallRefFuture => ty::AliasTy::new(
+                sym::CallRefFuture => ty::AliasTerm::new(
                     tcx,
                     obligation.predicate.def_id,
                     [
@@ -1885,7 +1909,7 @@
                 name => bug!("no such associated type: {name}"),
             };
 
-            bound_sig.rebind(ty::ProjectionPredicate { projection_ty, term: term.into() })
+            bound_sig.rebind(ty::ProjectionPredicate { projection_term, term: term.into() })
         }
         ty::Closure(_, args) => {
             let args = args.as_closure();
@@ -1906,11 +1930,11 @@
                 }
                 name => bug!("no such associated type: {name}"),
             };
-            let projection_ty = match item_name {
+            let projection_term = match item_name {
                 sym::CallOnceFuture | sym::Output => {
-                    ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.inputs()[0]])
+                    ty::AliasTerm::new(tcx, obligation.predicate.def_id, [self_ty, sig.inputs()[0]])
                 }
-                sym::CallRefFuture => ty::AliasTy::new(
+                sym::CallRefFuture => ty::AliasTerm::new(
                     tcx,
                     obligation.predicate.def_id,
                     [ty::GenericArg::from(self_ty), sig.inputs()[0].into(), env_region.into()],
@@ -1918,7 +1942,7 @@
                 name => bug!("no such associated type: {name}"),
             };
 
-            bound_sig.rebind(ty::ProjectionPredicate { projection_ty, term: term.into() })
+            bound_sig.rebind(ty::ProjectionPredicate { projection_term, term: term.into() })
         }
         _ => bug!("expected callable type for AsyncFn candidate"),
     };
@@ -1929,7 +1953,7 @@
 
 fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     nested: Vec<PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
     let [
@@ -1946,7 +1970,7 @@
     };
 
     let predicate = ty::ProjectionPredicate {
-        projection_ty: ty::AliasTy::new(
+        projection_term: ty::AliasTerm::new(
             selcx.tcx(),
             obligation.predicate.def_id,
             obligation.predicate.args,
@@ -1968,7 +1992,7 @@
 
 fn confirm_param_env_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     poly_cache_entry: ty::PolyProjectionPredicate<'tcx>,
     potentially_unnormalized_candidate: bool,
 ) -> Progress<'tcx> {
@@ -1982,7 +2006,7 @@
         poly_cache_entry,
     );
 
-    let cache_projection = cache_entry.projection_ty;
+    let cache_projection = cache_entry.projection_term;
     let mut nested_obligations = Vec::new();
     let obligation_projection = obligation.predicate;
     let obligation_projection = ensure_sufficient_stack(|| {
@@ -2037,7 +2061,7 @@
 
 fn confirm_impl_candidate<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     impl_impl_source: ImplSourceUserDefinedData<'tcx, PredicateObligation<'tcx>>,
 ) -> Progress<'tcx> {
     let tcx = selcx.tcx();
@@ -2098,7 +2122,7 @@
 // associated type itself.
 fn assoc_ty_own_obligations<'cx, 'tcx>(
     selcx: &mut SelectionContext<'cx, 'tcx>,
-    obligation: &ProjectionTyObligation<'tcx>,
+    obligation: &ProjectionTermObligation<'tcx>,
     nested: &mut Vec<PredicateObligation<'tcx>>,
 ) {
     let tcx = selcx.tcx();
@@ -2117,22 +2141,16 @@
 
         let nested_cause = if matches!(
             obligation.cause.code(),
-            super::CompareImplItemObligation { .. }
-                | super::CheckAssociatedTypeBounds { .. }
-                | super::AscribeUserTypeProvePredicate(..)
+            ObligationCauseCode::CompareImplItem { .. }
+                | ObligationCauseCode::CheckAssociatedTypeBounds { .. }
+                | ObligationCauseCode::AscribeUserTypeProvePredicate(..)
         ) {
             obligation.cause.clone()
-        } else if span.is_dummy() {
-            ObligationCause::new(
-                obligation.cause.span,
-                obligation.cause.body_id,
-                super::ItemObligation(obligation.predicate.def_id),
-            )
         } else {
             ObligationCause::new(
                 obligation.cause.span,
                 obligation.cause.body_id,
-                super::BindingObligation(obligation.predicate.def_id, span),
+                ObligationCauseCode::WhereClause(obligation.predicate.def_id, span),
             )
         };
         nested.push(Obligation::with_depth(
@@ -2166,7 +2184,7 @@
                 // from a specific call to `opt_normalize_projection_type` - if
                 // there's no precise match, the original cache entry is "stranded"
                 // anyway.
-                infcx.resolve_vars_if_possible(predicate.projection_ty),
+                infcx.resolve_vars_if_possible(predicate.projection_term),
                 obligation.param_env,
             )
         })
diff --git a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
index 87d240c..692feee 100644
--- a/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs
@@ -1,4 +1,5 @@
 use rustc_macros::extension;
+use rustc_middle::span_bug;
 
 use crate::infer::canonical::OriginalQueryValues;
 use crate::infer::InferCtxt;
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index 8b39c23..1b5ffee 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -222,7 +222,7 @@
                                 .infcx
                                 .err_ctxt()
                                 .build_overflow_error(
-                                    OverflowCause::DeeplyNormalize(data),
+                                    OverflowCause::DeeplyNormalize(data.into()),
                                     self.cause.span,
                                     true,
                                 )
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index f7e84a4..00cc77e 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -162,8 +162,7 @@
     let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
     let mut wf_args = vec![ty.into()];
 
-    let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> =
-        vec![];
+    let mut outlives_bounds: Vec<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>> = vec![];
 
     while let Some(arg) = wf_args.pop() {
         if !checked_wf_args.insert(arg) {
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
index 279d96d..e9948bf 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
@@ -34,7 +34,9 @@
     }
 }
 
-pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<TyCtxt<'tcx>> + Lift<'tcx> + Copy {
+pub trait Normalizable<'tcx>:
+    fmt::Debug + TypeFoldable<TyCtxt<'tcx>> + Lift<TyCtxt<'tcx>> + Copy
+{
     fn type_op_method(
         tcx: TyCtxt<'tcx>,
         canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 40d206b..b9e853a 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -16,6 +16,7 @@
 use rustc_infer::traits::{Obligation, PolyTraitObligation, SelectionError};
 use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
 use rustc_middle::ty::{self, ToPolyTraitRef, Ty, TypeVisitableExt};
+use rustc_middle::{bug, span_bug};
 
 use crate::traits;
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
@@ -944,7 +945,7 @@
         }
 
         self.infcx.probe(|_| {
-            let ty = traits::normalize_projection_type(
+            let ty = traits::normalize_projection_ty(
                 self,
                 param_env,
                 ty::AliasTy::new(tcx, tcx.lang_items().deref_target()?, trait_ref.args),
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 4fa2455..c684f08 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -11,11 +11,13 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::infer::HigherRankedType;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
+use rustc_infer::traits::ObligationCauseCode;
 use rustc_middle::traits::{BuiltinImplSource, SignatureMismatchData};
 use rustc_middle::ty::{
-    self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, ToPredicate,
-    TraitPredicate, Ty, TyCtxt,
+    self, GenericArgs, GenericArgsRef, GenericParamDefKind, ToPolyTraitRef, TraitPredicate, Ty,
+    TyCtxt, Upcast,
 };
+use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 
 use crate::traits::normalize::{normalize_with_depth, normalize_with_depth_to};
@@ -25,10 +27,9 @@
     VtblSegment,
 };
 use crate::traits::{
-    BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource,
-    ImplSourceUserDefinedData, Normalized, Obligation, ObligationCause, PolyTraitObligation,
-    PredicateObligation, Selection, SelectionError, SignatureMismatch, TraitNotObjectSafe,
-    TraitObligation, Unimplemented,
+    ImplDerivedCause, ImplSource, ImplSourceUserDefinedData, Normalized, Obligation,
+    ObligationCause, PolyTraitObligation, PredicateObligation, Selection, SelectionError,
+    SignatureMismatch, TraitNotObjectSafe, TraitObligation, Unimplemented,
 };
 
 use super::BuiltinImplConditions;
@@ -275,7 +276,7 @@
                 bug!("obligation {:?} had matched a builtin impl but now doesn't", obligation);
             };
 
-            let cause = obligation.derived_cause(BuiltinDerivedObligation);
+            let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
             self.collect_predicates_for_types(
                 obligation.param_env,
                 cause,
@@ -435,7 +436,7 @@
     ) -> Vec<PredicateObligation<'tcx>> {
         debug!(?nested, "vtable_auto_impl");
         ensure_sufficient_stack(|| {
-            let cause = obligation.derived_cause(BuiltinDerivedObligation);
+            let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
 
             let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
             let trait_ref = self.infcx.enter_forall_and_leak_universe(poly_trait_ref);
@@ -606,7 +607,7 @@
         for assoc_type in assoc_types {
             let defs: &ty::Generics = tcx.generics_of(assoc_type);
 
-            if !defs.params.is_empty() && !tcx.features().generic_associated_types_extended {
+            if !defs.own_params.is_empty() && !tcx.features().generic_associated_types_extended {
                 tcx.dcx().span_delayed_bug(
                     obligation.cause.span,
                     "GATs in trait object shouldn't have been considered",
@@ -618,7 +619,7 @@
             // higher-ranked things.
             // Prevent, e.g., `dyn Iterator<Item = str>`.
             for bound in self.tcx().item_bounds(assoc_type).transpose_iter() {
-                let arg_bound = if defs.count() == 0 {
+                let arg_bound = if defs.is_empty() {
                     bound.instantiate(tcx, trait_predicate.trait_ref.args)
                 } else {
                     let mut args = smallvec::SmallVec::with_capacity(defs.count());
@@ -675,7 +676,7 @@
                     let assoc_ty_args = tcx.mk_args(&args);
                     let bound =
                         bound.map_bound(|b| b.kind().skip_binder()).instantiate(tcx, assoc_ty_args);
-                    ty::Binder::bind_with_vars(bound, bound_vars).to_predicate(tcx)
+                    ty::Binder::bind_with_vars(bound, bound_vars).upcast(tcx)
                 };
                 let normalized_bound = normalize_with_depth_to(
                     self,
@@ -693,7 +694,8 @@
 
         let vtable_base = vtable_trait_first_method_offset(
             tcx,
-            (unnormalized_upcast_trait_ref, ty::Binder::dummy(object_trait_ref)),
+            unnormalized_upcast_trait_ref,
+            ty::Binder::dummy(object_trait_ref),
         );
 
         Ok(ImplSource::Builtin(BuiltinImplSource::Object { vtable_base: vtable_base }, nested))
@@ -722,7 +724,7 @@
 
         let mut nested =
             self.equate_trait_refs(obligation.with(tcx, placeholder_predicate), trait_ref)?;
-        let cause = obligation.derived_cause(BuiltinDerivedObligation);
+        let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
 
         // Confirm the `type Output: Sized;` bound that is present on `FnOnce`
         let output_ty = self.infcx.enter_forall_and_leak_universe(sig.output());
@@ -734,7 +736,11 @@
             output_ty,
             &mut nested,
         );
-        let tr = ty::TraitRef::from_lang_item(self.tcx(), LangItem::Sized, cause.span, [output_ty]);
+        let tr = ty::TraitRef::new(
+            self.tcx(),
+            self.tcx().require_lang_item(LangItem::Sized, Some(cause.span)),
+            [output_ty],
+        );
         nested.push(Obligation::new(self.infcx.tcx, cause, obligation.param_env, tr));
 
         Ok(nested)
@@ -1008,10 +1014,12 @@
         } else {
             nested.push(obligation.with(
                 self.tcx(),
-                ty::TraitRef::from_lang_item(
+                ty::TraitRef::new(
                     self.tcx(),
-                    LangItem::AsyncFnKindHelper,
-                    obligation.cause.span,
+                    self.tcx().require_lang_item(
+                        LangItem::AsyncFnKindHelper,
+                        Some(obligation.cause.span),
+                    ),
                     [kind_ty, Ty::from_closure_kind(self.tcx(), goal_kind)],
                 ),
             ));
@@ -1240,19 +1248,18 @@
                     .collect();
 
                 // We can only make objects from sized types.
-                let tr = ty::TraitRef::from_lang_item(
+                let tr = ty::TraitRef::new(
                     tcx,
-                    LangItem::Sized,
-                    obligation.cause.span,
+                    tcx.require_lang_item(LangItem::Sized, Some(obligation.cause.span)),
                     [source],
                 );
-                nested.push(predicate_to_obligation(tr.to_predicate(tcx)));
+                nested.push(predicate_to_obligation(tr.upcast(tcx)));
 
                 // If the type is `Foo + 'a`, ensure that the type
                 // being cast to `Foo + 'a` outlives `'a`:
                 let outlives = ty::OutlivesPredicate(source, r);
                 nested.push(predicate_to_obligation(
-                    ty::Binder::dummy(ty::ClauseKind::TypeOutlives(outlives)).to_predicate(tcx),
+                    ty::ClauseKind::TypeOutlives(outlives).upcast(tcx),
                 ));
 
                 ImplSource::Builtin(BuiltinImplSource::Misc, nested)
@@ -1380,7 +1387,7 @@
         let self_ty = obligation.self_ty().map_bound(|ty| self.infcx.shallow_resolve(ty));
 
         let mut nested = vec![];
-        let cause = obligation.derived_cause(BuiltinDerivedObligation);
+        let cause = obligation.derived_cause(ObligationCauseCode::BuiltinDerived);
 
         // If we have a custom `impl const Drop`, then
         // first check it like a regular impl candidate.
@@ -1395,7 +1402,7 @@
             debug!(?args, "impl args");
 
             let cause = obligation.derived_cause(|derived| {
-                ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
+                ObligationCauseCode::ImplDerived(Box::new(ImplDerivedCause {
                     derived,
                     impl_or_alias_def_id: impl_def_id,
                     impl_def_predicate_index: None,
@@ -1473,10 +1480,9 @@
                         cause.clone(),
                         obligation.recursion_depth + 1,
                         self_ty.rebind(ty::TraitPredicate {
-                            trait_ref: ty::TraitRef::from_lang_item(
+                            trait_ref: ty::TraitRef::new(
                                 self.tcx(),
-                                LangItem::Destruct,
-                                cause.span,
+                                self.tcx().require_lang_item(LangItem::Destruct, Some(cause.span)),
                                 [nested_ty.into(), host_effect_param],
                             ),
                             polarity: ty::PredicatePolarity::Positive,
@@ -1506,10 +1512,9 @@
                 | ty::Infer(_)
                 | ty::Placeholder(_) => {
                     let predicate = self_ty.rebind(ty::TraitPredicate {
-                        trait_ref: ty::TraitRef::from_lang_item(
+                        trait_ref: ty::TraitRef::new(
                             self.tcx(),
-                            LangItem::Destruct,
-                            cause.span,
+                            self.tcx().require_lang_item(LangItem::Destruct, Some(cause.span)),
                             [nested_ty.into(), host_effect_param],
                         ),
                         polarity: ty::PredicatePolarity::Positive,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 18cb318..4a94643 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -8,14 +8,14 @@
 use super::coherence::{self, Conflict};
 use super::const_evaluatable;
 use super::project;
-use super::project::ProjectionTyObligation;
+use super::project::ProjectionTermObligation;
 use super::util;
 use super::util::closure_trait_ref_and_return_type;
 use super::wf;
 use super::{
-    ImplDerivedObligation, ImplDerivedObligationCause, Normalized, Obligation, ObligationCause,
-    ObligationCauseCode, Overflow, PolyTraitObligation, PredicateObligation, Selection,
-    SelectionError, SelectionResult, TraitQueryMode,
+    ImplDerivedCause, Normalized, Obligation, ObligationCause, ObligationCauseCode, Overflow,
+    PolyTraitObligation, PredicateObligation, Selection, SelectionError, SelectionResult,
+    TraitQueryMode,
 };
 
 use crate::infer::{InferCtxt, InferOk, TypeFreshener};
@@ -36,14 +36,16 @@
 use rustc_infer::infer::BoundRegionConversionTime::HigherRankedType;
 use rustc_infer::infer::DefineOpaqueTypes;
 use rustc_infer::traits::TraitObligation;
+use rustc_middle::bug;
 use rustc_middle::dep_graph::dep_kinds;
 use rustc_middle::dep_graph::DepNodeIndex;
 use rustc_middle::mir::interpret::ErrorHandled;
 use rustc_middle::ty::_match::MatchAgainstFreshVars;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
+use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::relate::TypeRelation;
 use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, PolyProjectionPredicate, ToPredicate};
+use rustc_middle::ty::{self, PolyProjectionPredicate, Upcast};
 use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
 use rustc_span::symbol::sym;
 use rustc_span::Symbol;
@@ -737,8 +739,7 @@
                             // stack would be `T: Auto`.
                             let cycle = stack.iter().take_while(|s| s.depth > stack_arg.1);
                             let tcx = self.tcx();
-                            let cycle =
-                                cycle.map(|stack| stack.obligation.predicate.to_predicate(tcx));
+                            let cycle = cycle.map(|stack| stack.obligation.predicate.upcast(tcx));
                             if self.coinductive_match(cycle) {
                                 stack.update_reached_depth(stack_arg.1);
                                 return Ok(EvaluatedToOk);
@@ -807,7 +808,7 @@
                 ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
                     let data = bound_predicate.rebind(data);
                     let project_obligation = obligation.with(self.tcx(), data);
-                    match project::poly_project_and_unify_type(self, &project_obligation) {
+                    match project::poly_project_and_unify_term(self, &project_obligation) {
                         ProjectAndUnifyResult::Holds(mut subobligations) => {
                             'compute_res: {
                                 // If we've previously marked this projection as 'complete', then
@@ -1172,7 +1173,7 @@
             // if the regions match exactly.
             let cycle = stack.iter().skip(1).take_while(|s| s.depth >= cycle_depth);
             let tcx = self.tcx();
-            let cycle = cycle.map(|stack| stack.obligation.predicate.to_predicate(tcx));
+            let cycle = cycle.map(|stack| stack.obligation.predicate.upcast(tcx));
             if self.coinductive_match(cycle) {
                 debug!("evaluate_stack --> recursive, coinductive");
                 Some(EvaluatedToOk)
@@ -1377,7 +1378,7 @@
         error_obligation: &Obligation<'tcx, T>,
     ) -> Result<(), OverflowError>
     where
-        T: ToPredicate<'tcx> + Clone,
+        T: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + Clone,
     {
         if !self.infcx.tcx.recursion_limit().value_within_limit(depth) {
             match self.query_mode {
@@ -1406,7 +1407,7 @@
         error_obligation: &Obligation<'tcx, V>,
     ) -> Result<(), OverflowError>
     where
-        V: ToPredicate<'tcx> + Clone,
+        V: Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + Clone,
     {
         self.check_recursion_depth(obligation.recursion_depth, error_obligation)
     }
@@ -1732,7 +1733,7 @@
     /// in cases like #91762.
     pub(super) fn match_projection_projections(
         &mut self,
-        obligation: &ProjectionTyObligation<'tcx>,
+        obligation: &ProjectionTermObligation<'tcx>,
         env_predicate: PolyProjectionPredicate<'tcx>,
         potentially_unnormalized_candidates: bool,
     ) -> ProjectionMatchesProjection {
@@ -1751,12 +1752,12 @@
                     obligation.param_env,
                     obligation.cause.clone(),
                     obligation.recursion_depth + 1,
-                    infer_predicate.projection_ty,
+                    infer_predicate.projection_term,
                     &mut nested_obligations,
                 )
             })
         } else {
-            infer_predicate.projection_ty
+            infer_predicate.projection_term
         };
 
         let is_match = self
@@ -1777,9 +1778,19 @@
             // If this type is a GAT, and of the GAT args resolve to something new,
             // that means that we must have newly inferred something about the GAT.
             // We should give up in that case.
-            if !generics.params.is_empty()
+            // FIXME(generic-associated-types): This only detects one layer of inference,
+            // which is probably not what we actually want, but fixing it causes some ambiguity:
+            // <https://github.com/rust-lang/rust/issues/125196>.
+            if !generics.is_own_empty()
                 && obligation.predicate.args[generics.parent_count..].iter().any(|&p| {
-                    p.has_non_region_infer() && self.infcx.resolve_vars_if_possible(p) != p
+                    p.has_non_region_infer()
+                        && match p.unpack() {
+                            ty::GenericArgKind::Const(ct) => {
+                                self.infcx.shallow_resolve_const(ct) != ct
+                            }
+                            ty::GenericArgKind::Type(ty) => self.infcx.shallow_resolve(ty) != ty,
+                            ty::GenericArgKind::Lifetime(_) => false,
+                        }
                 })
             {
                 ProjectionMatchesProjection::Ambiguous
@@ -2441,7 +2452,7 @@
                     });
 
                 let tcx = self.tcx();
-                let trait_ref = if tcx.generics_of(trait_def_id).params.len() == 1 {
+                let trait_ref = if tcx.generics_of(trait_def_id).own_params.len() == 1 {
                     ty::TraitRef::new(tcx, trait_def_id, [normalized_ty])
                 } else {
                     // If this is an ill-formed auto/built-in trait, then synthesize
@@ -2771,7 +2782,7 @@
                     cause.clone()
                 } else {
                     cause.clone().derived_cause(parent_trait_pred, |derived| {
-                        ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
+                        ObligationCauseCode::ImplDerived(Box::new(ImplDerivedCause {
                             derived,
                             impl_or_alias_def_id: def_id,
                             impl_def_predicate_index: Some(index),
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 390e711..826bb70 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -11,6 +11,7 @@
 
 pub mod specialization_graph;
 use rustc_infer::infer::DefineOpaqueTypes;
+use rustc_middle::ty::print::PrintTraitRefExt as _;
 use specialization_graph::GraphExt;
 
 use crate::errors::NegativePositiveConflict;
@@ -22,6 +23,7 @@
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{codes::*, DelayDm, Diag, EmissionGuarantee};
 use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_middle::bug;
 use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt};
 use rustc_middle::ty::{GenericArgs, GenericArgsRef};
 use rustc_session::lint::builtin::COHERENCE_LEAK_CHECK;
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index b6c2fcb..90f2c7a 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -4,6 +4,7 @@
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
 use rustc_macros::extension;
+use rustc_middle::bug;
 use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
 use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
 
diff --git a/compiler/rustc_trait_selection/src/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs
index 6778ac8..d4535db 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_match.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs
@@ -1,5 +1,6 @@
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir as hir;
+use rustc_middle::bug;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
 use std::ops::ControlFlow;
 
diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
index 64ab837..96a06e0 100644
--- a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
@@ -1,5 +1,4 @@
 use rustc_infer::infer::at::At;
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
 use rustc_infer::traits::{FulfillmentError, TraitEngine};
 use rustc_macros::extension;
 use rustc_middle::ty::{self, Ty};
@@ -20,9 +19,7 @@
                 return Ok(ty);
             };
 
-            let new_infer_ty = self
-                .infcx
-                .next_ty_var(TypeVariableOrigin { param_def_id: None, span: self.cause.span });
+            let new_infer_ty = self.infcx.next_ty_var(self.cause.span);
 
             // We simply emit an `alias-eq` goal here, since that will take care of
             // normalizing the LHS of the projection until it is a rigid projection
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index b2ba785..445fa17 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -6,8 +6,9 @@
 use rustc_errors::Diag;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::{InferCtxt, InferOk};
+use rustc_middle::bug;
 use rustc_middle::ty::GenericArgsRef;
-use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitableExt, Upcast};
 use rustc_middle::ty::{TypeFoldable, TypeFolder, TypeSuperFoldable};
 use rustc_span::Span;
 use smallvec::{smallvec, SmallVec};
@@ -104,7 +105,7 @@
     fn expand(&mut self, item: &TraitAliasExpansionInfo<'tcx>) -> bool {
         let tcx = self.tcx;
         let trait_ref = item.trait_ref();
-        let pred = trait_ref.to_predicate(tcx);
+        let pred = trait_ref.upcast(tcx);
 
         debug!("expand_trait_aliases: trait_ref={:?}", trait_ref);
 
@@ -121,7 +122,7 @@
             .iter()
             .rev()
             .skip(1)
-            .any(|&(tr, _)| anonymize_predicate(tcx, tr.to_predicate(tcx)) == anon_pred)
+            .any(|&(tr, _)| anonymize_predicate(tcx, tr.upcast(tcx)) == anon_pred)
         {
             return false;
         }
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index 178f3c6..c93ec43 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -4,11 +4,12 @@
 use rustc_hir::lang_items::LangItem;
 use rustc_infer::traits::util::PredicateSet;
 use rustc_infer::traits::ImplSource;
+use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::BuiltinImplSource;
 use rustc_middle::ty::visit::TypeVisitableExt;
 use rustc_middle::ty::GenericArgs;
-use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
+use rustc_middle::ty::{self, GenericParamDefKind, Ty, TyCtxt, Upcast, VtblEntry};
 use rustc_span::{sym, Span};
 use smallvec::{smallvec, SmallVec};
 
@@ -86,7 +87,7 @@
 
     let mut emit_vptr_on_new_entry = false;
     let mut visited = PredicateSet::new(tcx);
-    let predicate = trait_ref.to_predicate(tcx);
+    let predicate = trait_ref.upcast(tcx);
     let mut stack: SmallVec<[(ty::PolyTraitRef<'tcx>, _, _); 5]> =
         smallvec![(trait_ref, emit_vptr_on_new_entry, maybe_iter(None))];
     visited.insert(predicate);
@@ -129,7 +130,7 @@
 
             // Find an unvisited supertrait
             match direct_super_traits_iter
-                .find(|&super_trait| visited.insert(super_trait.to_predicate(tcx)))
+                .find(|&super_trait| visited.insert(super_trait.upcast(tcx)))
             {
                 // Push it to the stack for the next iteration of 'diving_in to pick up
                 Some(unvisited_super_trait) => {
@@ -164,7 +165,7 @@
             }
 
             if let Some(next_inner_most_trait_ref) =
-                siblings.find(|&sibling| visited.insert(sibling.to_predicate(tcx)))
+                siblings.find(|&sibling| visited.insert(sibling.upcast(tcx)))
             {
                 // We're throwing away potential constness of super traits here.
                 // FIXME: handle ~const super traits
@@ -320,16 +321,11 @@
 }
 
 /// Find slot base for trait methods within vtable entries of another trait
-// FIXME(@lcnr): This isn't a query, so why does it take a tuple as its argument.
 pub(super) fn vtable_trait_first_method_offset<'tcx>(
     tcx: TyCtxt<'tcx>,
-    key: (
-        ty::PolyTraitRef<'tcx>, // trait_to_be_found
-        ty::PolyTraitRef<'tcx>, // trait_owning_vtable
-    ),
+    trait_to_be_found: ty::PolyTraitRef<'tcx>,
+    trait_owning_vtable: ty::PolyTraitRef<'tcx>,
 ) -> usize {
-    let (trait_to_be_found, trait_owning_vtable) = key;
-
     // #90177
     let trait_to_be_found_erased = tcx.erase_regions(trait_to_be_found);
 
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 28ee76f..f4189ff 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -2,6 +2,8 @@
 use crate::traits;
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
+use rustc_infer::traits::ObligationCauseCode;
+use rustc_middle::bug;
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
@@ -164,11 +166,8 @@
             wf.compute(ty.into());
         }
         ty::ClauseKind::Projection(t) => {
-            wf.compute_alias(t.projection_ty);
-            wf.compute(match t.term.unpack() {
-                ty::TermKind::Ty(ty) => ty.into(),
-                ty::TermKind::Const(c) => c.into(),
-            })
+            wf.compute_alias_term(t.projection_term);
+            wf.compute(t.term.into_arg());
         }
         ty::ClauseKind::ConstArgHasType(ct, ty) => {
             wf.compute(ct.into());
@@ -333,7 +332,7 @@
             return self.out;
         }
 
-        let cause = self.cause(traits::WellFormed(None));
+        let cause = self.cause(ObligationCauseCode::WellFormed(None));
         let param_env = self.param_env;
         let mut obligations = Vec::with_capacity(self.out.len());
         for mut obligation in self.out {
@@ -378,10 +377,10 @@
         let item = self.item;
 
         let extend = |traits::PredicateObligation { predicate, mut cause, .. }| {
-            if let Some(parent_trait_pred) = predicate.to_opt_poly_trait_pred() {
+            if let Some(parent_trait_pred) = predicate.as_trait_clause() {
                 cause = cause.derived_cause(
                     parent_trait_pred,
-                    traits::ObligationCauseCode::WellFormedDerivedObligation,
+                    traits::ObligationCauseCode::WellFormedDerived,
                 );
             }
             extend_cause_with_original_assoc_item_obligation(tcx, item, &mut cause, predicate);
@@ -438,7 +437,13 @@
 
     /// Pushes the obligations required for an alias (except inherent) to be WF
     /// into `self.out`.
-    fn compute_alias(&mut self, data: ty::AliasTy<'tcx>) {
+    fn compute_alias_ty(&mut self, data: ty::AliasTy<'tcx>) {
+        self.compute_alias_term(data.into());
+    }
+
+    /// Pushes the obligations required for an alias (except inherent) to be WF
+    /// into `self.out`.
+    fn compute_alias_term(&mut self, data: ty::AliasTerm<'tcx>) {
         // A projection is well-formed if
         //
         // (a) its predicates hold (*)
@@ -485,7 +490,7 @@
                 &mut traits::SelectionContext::new(self.infcx),
                 self.param_env,
                 data,
-                self.cause(traits::WellFormed(None)),
+                self.cause(ObligationCauseCode::WellFormed(None)),
                 self.recursion_depth,
                 &mut self.out,
             );
@@ -498,7 +503,7 @@
 
     fn compute_projection_args(&mut self, args: GenericArgsRef<'tcx>) {
         let tcx = self.tcx();
-        let cause = self.cause(traits::WellFormed(None));
+        let cause = self.cause(ObligationCauseCode::WellFormed(None));
         let param_env = self.param_env;
         let depth = self.recursion_depth;
 
@@ -525,8 +530,11 @@
     fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
         if !subty.has_escaping_bound_vars() {
             let cause = self.cause(cause);
-            let trait_ref =
-                ty::TraitRef::from_lang_item(self.tcx(), LangItem::Sized, cause.span, [subty]);
+            let trait_ref = ty::TraitRef::new(
+                self.tcx(),
+                self.tcx().require_lang_item(LangItem::Sized, Some(cause.span)),
+                [subty],
+            );
             self.out.push(traits::Obligation::with_depth(
                 self.tcx(),
                 cause,
@@ -564,11 +572,7 @@
 
         iter::zip(predicates, origins.into_iter().rev())
             .map(|((pred, span), origin_def_id)| {
-                let code = if span.is_dummy() {
-                    traits::ItemObligation(origin_def_id)
-                } else {
-                    traits::BindingObligation(origin_def_id, span)
-                };
+                let code = ObligationCauseCode::WhereClause(origin_def_id, span);
                 let cause = self.cause(code);
                 traits::Obligation::with_depth(
                     self.tcx(),
@@ -626,7 +630,7 @@
 
             self.out.reserve(implicit_bounds.len());
             for implicit_bound in implicit_bounds {
-                let cause = self.cause(traits::ObjectTypeBound(ty, explicit_bound));
+                let cause = self.cause(ObligationCauseCode::ObjectTypeBound(ty, explicit_bound));
                 let outlives =
                     ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound));
                 self.out.push(traits::Obligation::with_depth(
@@ -644,7 +648,7 @@
 impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
     type Result = ();
 
-    fn visit_ty(&mut self, t: <TyCtxt<'tcx> as ty::Interner>::Ty) -> Self::Result {
+    fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result {
         debug!("wf bounds for t={:?} t.kind={:#?}", t, t.kind());
 
         let tcx = self.tcx();
@@ -673,22 +677,22 @@
             ty::Infer(ty::FloatVar(_)) => {}
 
             ty::Slice(subty) => {
-                self.require_sized(subty, traits::SliceOrArrayElem);
+                self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem);
             }
 
             ty::Array(subty, _) => {
-                self.require_sized(subty, traits::SliceOrArrayElem);
+                self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem);
                 // Note that we handle the len is implicitly checked while walking `arg`.
             }
 
             ty::Pat(subty, _) => {
-                self.require_sized(subty, traits::MiscObligation);
+                self.require_sized(subty, ObligationCauseCode::Misc);
             }
 
             ty::Tuple(tys) => {
                 if let Some((_last, rest)) = tys.split_last() {
                     for &elem in rest {
-                        self.require_sized(elem, traits::TupleElem);
+                        self.require_sized(elem, ObligationCauseCode::TupleElem);
                     }
                 }
             }
@@ -698,7 +702,7 @@
             }
 
             ty::Alias(ty::Projection | ty::Opaque | ty::Weak, data) => {
-                self.compute_alias(data);
+                self.compute_alias_ty(data);
                 return; // Subtree handled by compute_projection.
             }
             ty::Alias(ty::Inherent, data) => {
@@ -728,7 +732,7 @@
             ty::Ref(r, rty, _) => {
                 // WfReference
                 if !r.has_escaping_bound_vars() && !rty.has_escaping_bound_vars() {
-                    let cause = self.cause(traits::ReferenceOutlivesReferent(t));
+                    let cause = self.cause(ObligationCauseCode::ReferenceOutlivesReferent(t));
                     self.out.push(traits::Obligation::with_depth(
                         tcx,
                         cause,
@@ -825,7 +829,7 @@
                     if let Some(principal) = data.principal_def_id() {
                         self.out.push(traits::Obligation::with_depth(
                             tcx,
-                            self.cause(traits::WellFormed(None)),
+                            self.cause(ObligationCauseCode::WellFormed(None)),
                             self.recursion_depth,
                             self.param_env,
                             ty::Binder::dummy(ty::PredicateKind::ObjectSafe(principal)),
@@ -847,7 +851,7 @@
             // See also the comment on `fn obligations`, describing "livelock"
             // prevention, which happens before this can be reached.
             ty::Infer(_) => {
-                let cause = self.cause(traits::WellFormed(None));
+                let cause = self.cause(ObligationCauseCode::WellFormed(None));
                 self.out.push(traits::Obligation::with_depth(
                     tcx,
                     cause,
@@ -863,7 +867,7 @@
         t.super_visit_with(self)
     }
 
-    fn visit_const(&mut self, c: <TyCtxt<'tcx> as ty::Interner>::Const) -> Self::Result {
+    fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result {
         let tcx = self.tcx();
 
         match c.kind() {
@@ -875,7 +879,7 @@
                     let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(
                         ty::ClauseKind::ConstEvaluatable(c),
                     ));
-                    let cause = self.cause(traits::WellFormed(None));
+                    let cause = self.cause(ObligationCauseCode::WellFormed(None));
                     self.out.push(traits::Obligation::with_depth(
                         tcx,
                         cause,
@@ -886,7 +890,7 @@
                 }
             }
             ty::ConstKind::Infer(_) => {
-                let cause = self.cause(traits::WellFormed(None));
+                let cause = self.cause(ObligationCauseCode::WellFormed(None));
 
                 self.out.push(traits::Obligation::with_depth(
                     tcx,
@@ -909,7 +913,7 @@
                 let predicate = ty::Binder::dummy(ty::PredicateKind::Clause(
                     ty::ClauseKind::ConstEvaluatable(c),
                 ));
-                let cause = self.cause(traits::WellFormed(None));
+                let cause = self.cause(ObligationCauseCode::WellFormed(None));
                 self.out.push(traits::Obligation::with_depth(
                     tcx,
                     cause,
@@ -933,7 +937,7 @@
         c.super_visit_with(self)
     }
 
-    fn visit_predicate(&mut self, _p: <TyCtxt<'tcx> as ty::Interner>::Predicate) -> Self::Result {
+    fn visit_predicate(&mut self, _p: ty::Predicate<'tcx>) -> Self::Result {
         bug!("predicate should not be checked for well-formedness");
     }
 }
diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs
index 559c05eb..fee1307 100644
--- a/compiler/rustc_traits/src/normalize_projection_ty.rs
+++ b/compiler/rustc_traits/src/normalize_projection_ty.rs
@@ -34,14 +34,8 @@
             let selcx = &mut SelectionContext::new(ocx.infcx);
             let cause = ObligationCause::dummy();
             let mut obligations = vec![];
-            let answer = traits::normalize_projection_type(
-                selcx,
-                param_env,
-                goal,
-                cause,
-                0,
-                &mut obligations,
-            );
+            let answer =
+                traits::normalize_projection_ty(selcx, param_env, goal, cause, 0, &mut obligations);
             ocx.register_obligations(obligations);
             // #112047: With projections and opaques, we are able to create opaques that
             // are recursive (given some generic parameters of the opaque's type variables).
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index 01b9a56..b6a59a4 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -3,7 +3,7 @@
 use rustc_middle::query::Providers;
 use rustc_middle::traits::query::NoSolution;
 use rustc_middle::ty::{Clause, ParamEnvAnd};
-use rustc_middle::ty::{FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{FnSig, PolyFnSig, Ty, TyCtxt, TypeFoldable};
 use rustc_trait_selection::infer::InferCtxtBuilderExt;
 use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{
@@ -54,7 +54,7 @@
     key: ParamEnvAnd<'tcx, Normalize<T>>,
 ) -> Result<T, NoSolution>
 where
-    T: fmt::Debug + TypeFoldable<TyCtxt<'tcx>> + Lift<'tcx>,
+    T: fmt::Debug + TypeFoldable<TyCtxt<'tcx>>,
 {
     let (param_env, Normalize { value }) = key.into_parts();
     let Normalized { value, obligations } =
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index c6b8362..9090bb3 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -1,5 +1,6 @@
 use rustc_hir as hir;
 use rustc_hir::lang_items::LangItem;
+use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::layout::{
     fn_can_unwind, FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout,
@@ -36,7 +37,7 @@
             [],
             tcx.thread_local_ptr_ty(instance.def_id()),
             false,
-            hir::Unsafety::Normal,
+            hir::Safety::Safe,
             rustc_target::spec::abi::Abi::Unadjusted,
         ));
     }
@@ -95,7 +96,7 @@
                     iter::once(env_ty).chain(sig.inputs().iter().cloned()),
                     sig.output(),
                     sig.c_variadic,
-                    sig.unsafety,
+                    sig.safety,
                     sig.abi,
                 ),
                 bound_vars,
@@ -149,7 +150,7 @@
                         args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
                     ),
                     sig.c_variadic,
-                    sig.unsafety,
+                    sig.safety,
                     sig.abi,
                 ),
                 bound_vars,
@@ -300,7 +301,7 @@
                     [env_ty, resume_ty],
                     ret_ty,
                     false,
-                    hir::Unsafety::Normal,
+                    hir::Safety::Safe,
                     rustc_target::spec::abi::Abi::Rust,
                 )
             } else {
@@ -309,7 +310,7 @@
                     [env_ty],
                     ret_ty,
                     false,
-                    hir::Unsafety::Normal,
+                    hir::Safety::Safe,
                     rustc_target::spec::abi::Abi::Rust,
                 )
             };
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index ba75424..4395eb5 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -5,6 +5,7 @@
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, ImplTraitInTraitData, TyCtxt};
+use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::kw;
 
 pub(crate) fn provide(providers: &mut Providers) {
@@ -340,22 +341,22 @@
     impl_assoc_ty.generics_of({
         let trait_assoc_generics = tcx.generics_of(trait_assoc_def_id);
         let trait_assoc_parent_count = trait_assoc_generics.parent_count;
-        let mut params = trait_assoc_generics.params.clone();
+        let mut own_params = trait_assoc_generics.own_params.clone();
 
         let parent_generics = tcx.generics_of(impl_local_def_id.to_def_id());
-        let parent_count = parent_generics.parent_count + parent_generics.params.len();
+        let parent_count = parent_generics.parent_count + parent_generics.own_params.len();
 
-        for param in &mut params {
+        for param in &mut own_params {
             param.index = param.index + parent_count as u32 - trait_assoc_parent_count as u32;
         }
 
         let param_def_id_to_index =
-            params.iter().map(|param| (param.def_id, param.index)).collect();
+            own_params.iter().map(|param| (param.def_id, param.index)).collect();
 
         ty::Generics {
             parent: Some(impl_local_def_id.to_def_id()),
             parent_count,
-            params,
+            own_params,
             param_def_id_to_index,
             has_self: false,
             has_late_bound_regions: trait_assoc_generics.has_late_bound_regions,
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index acbcc39..b40a0d0 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -1,6 +1,7 @@
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
+use rustc_middle::bug;
 use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
 use rustc_middle::query::Providers;
 use rustc_middle::thir::visit;
@@ -80,9 +81,9 @@
 fn check_binop(op: mir::BinOp) -> bool {
     use mir::BinOp::*;
     match op {
-        Add | AddUnchecked | Sub | SubUnchecked | Mul | MulUnchecked | Div | Rem | BitXor
-        | BitAnd | BitOr | Shl | ShlUnchecked | Shr | ShrUnchecked | Eq | Lt | Le | Ne | Ge
-        | Gt | Cmp => true,
+        Add | AddUnchecked | AddWithOverflow | Sub | SubUnchecked | SubWithOverflow | Mul
+        | MulUnchecked | MulWithOverflow | Div | Rem | BitXor | BitAnd | BitOr | Shl
+        | ShlUnchecked | Shr | ShrUnchecked | Eq | Lt | Le | Ne | Ge | Gt | Cmp => true,
         Offset => false,
     }
 }
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index e1534af..e87058f 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -2,6 +2,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::LocalDefId;
+use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
@@ -69,7 +70,8 @@
                     // case, since it has been liberated), map it back to the early-bound lifetime of
                     // the GAT. Since RPITITs also have all of the fn's generics, we slice only
                     // the end of the list corresponding to the opaque's generics.
-                    for param in &generics.params[tcx.generics_of(fn_def_id).params.len()..] {
+                    for param in &generics.own_params[tcx.generics_of(fn_def_id).own_params.len()..]
+                    {
                         let orig_lt =
                             tcx.map_opaque_lifetime_to_parent_lifetime(param.def_id.expect_local());
                         if matches!(*orig_lt, ty::ReLateParam(..)) {
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index d0aa4eb..41f482d 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -1,6 +1,7 @@
 use rustc_errors::ErrorGuaranteed;
 use rustc_hir::def_id::DefId;
 use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::traits::{BuiltinImplSource, CodegenObligationError};
 use rustc_middle::ty::GenericArgsRef;
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 902b76e..1ef2249 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -2,10 +2,11 @@
 use rustc_hir as hir;
 use rustc_index::bit_set::BitSet;
 use rustc_index::{IndexSlice, IndexVec};
+use rustc_middle::bug;
 use rustc_middle::mir::{CoroutineLayout, CoroutineSavedLocal};
 use rustc_middle::query::Providers;
 use rustc_middle::ty::layout::{
-    IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
+    FloatExt, IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
 };
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{
@@ -180,12 +181,7 @@
         )),
         ty::Int(ity) => scalar(Int(Integer::from_int_ty(dl, ity), true)),
         ty::Uint(ity) => scalar(Int(Integer::from_uint_ty(dl, ity), false)),
-        ty::Float(fty) => scalar(match fty {
-            ty::FloatTy::F16 => F16,
-            ty::FloatTy::F32 => F32,
-            ty::FloatTy::F64 => F64,
-            ty::FloatTy::F128 => F128,
-        }),
+        ty::Float(fty) => scalar(Float(Float::from_float_ty(fty))),
         ty::FnPtr(_) => {
             let mut ptr = scalar_unit(Pointer(dl.instruction_address_space));
             ptr.valid_range_mut().start = 1;
diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
index 6332c61..ab7d1be 100644
--- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs
+++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
@@ -1,3 +1,4 @@
+use rustc_middle::bug;
 use rustc_middle::ty::{
     layout::{LayoutCx, TyAndLayout},
     TyCtxt,
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index fd392d1..e8c5c54 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -17,8 +17,6 @@
 #![feature(never_type)]
 
 #[macro_use]
-extern crate rustc_middle;
-#[macro_use]
 extern crate tracing;
 
 use rustc_middle::query::Providers;
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index ee930a7..4e23fb3 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -2,6 +2,7 @@
 
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::def_id::DefId;
+use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop};
 use rustc_middle::ty::GenericArgsRef;
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
index d7d31a8..be227ec 100644
--- a/compiler/rustc_ty_utils/src/opaque_types.rs
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -2,6 +2,7 @@
 use rustc_hir::intravisit::Visitor;
 use rustc_hir::{def::DefKind, def_id::LocalDefId};
 use rustc_hir::{intravisit, CRATE_HIR_ID};
+use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::util::{CheckRegions, NotUniqueParam};
 use rustc_middle::ty::{self, Ty, TyCtxt};
diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs
index a5ffa55..0ffb7f6 100644
--- a/compiler/rustc_ty_utils/src/representability.rs
+++ b/compiler/rustc_ty_utils/src/representability.rs
@@ -1,5 +1,6 @@
 use rustc_hir::def::DefKind;
 use rustc_index::bit_set::BitSet;
+use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, Representability, Ty, TyCtxt};
 use rustc_span::def_id::LocalDefId;
@@ -85,7 +86,7 @@
 fn params_in_repr(tcx: TyCtxt<'_>, def_id: LocalDefId) -> BitSet<u32> {
     let adt_def = tcx.adt_def(def_id);
     let generics = tcx.generics_of(def_id);
-    let mut params_in_repr = BitSet::new_empty(generics.params.len());
+    let mut params_in_repr = BitSet::new_empty(generics.own_params.len());
     for variant in adt_def.variants() {
         for field in variant.fields.iter() {
             params_in_repr_ty(
diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs
index 19c092c..2d8c782 100644
--- a/compiler/rustc_ty_utils/src/sig_types.rs
+++ b/compiler/rustc_ty_utils/src/sig_types.rs
@@ -4,6 +4,7 @@
 use rustc_ast_ir::try_visit;
 use rustc_ast_ir::visit::VisitorResult;
 use rustc_hir::{def::DefKind, def_id::LocalDefId};
+use rustc_middle::span_bug;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_span::Span;
 use rustc_type_ir::visit::TypeVisitable;
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index fa1085c..3094956 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -3,9 +3,10 @@
 use rustc_hir::def::DefKind;
 use rustc_hir::LangItem;
 use rustc_index::bit_set::BitSet;
+use rustc_middle::bug;
 use rustc_middle::query::Providers;
 use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt, TypeVisitableExt, TypeVisitor};
-use rustc_middle::ty::{ToPredicate, TypeSuperVisitable, TypeVisitable};
+use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, Upcast};
 use rustc_span::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits;
@@ -214,12 +215,12 @@
             self.predicates.push(
                 ty::Binder::bind_with_vars(
                     ty::ProjectionPredicate {
-                        projection_ty: shifted_alias_ty,
+                        projection_term: shifted_alias_ty.into(),
                         term: default_ty.into(),
                     },
                     self.bound_vars,
                 )
-                .to_predicate(self.tcx),
+                .upcast(self.tcx),
             );
 
             // We walk the *un-shifted* alias ty, because we're tracking the de bruijn
diff --git a/compiler/rustc_type_ir/Cargo.toml b/compiler/rustc_type_ir/Cargo.toml
index 79ff608..cef3f4e 100644
--- a/compiler/rustc_type_ir/Cargo.toml
+++ b/compiler/rustc_type_ir/Cargo.toml
@@ -13,7 +13,8 @@
 rustc_macros = { path = "../rustc_macros", optional = true }
 rustc_serialize = { path = "../rustc_serialize", optional = true }
 rustc_span = { path = "../rustc_span", optional = true }
-smallvec = { version = "1.8.1" }
+rustc_type_ir_macros = { path = "../rustc_type_ir_macros" }
+smallvec = { version = "1.8.1", default-features = false }
 # tidy-alphabetical-end
 
 [features]
diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs
index 57f961a..5336b91 100644
--- a/compiler/rustc_type_ir/src/binder.rs
+++ b/compiler/rustc_type_ir/src/binder.rs
@@ -1,7 +1,340 @@
-use crate::Interner;
+use std::fmt::Debug;
+use std::hash::Hash;
+use std::ops::{ControlFlow, Deref};
 
-pub trait BoundVars<I: Interner> {
-    fn bound_vars(&self) -> I::BoundVars;
+#[cfg(feature = "nightly")]
+use rustc_macros::HashStable_NoContext;
+use rustc_serialize::Decodable;
 
-    fn has_no_bound_vars(&self) -> bool;
+use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
+use crate::inherent::*;
+use crate::lift::Lift;
+use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
+use crate::{self as ty, Interner, SsoHashSet};
+
+/// Binder is a binder for higher-ranked lifetimes or types. It is part of the
+/// compiler's representation for things like `for<'a> Fn(&'a isize)`
+/// (which would be represented by the type `PolyTraitRef ==
+/// Binder<I, TraitRef>`). Note that when we instantiate,
+/// erase, or otherwise "discharge" these bound vars, we change the
+/// type from `Binder<I, T>` to just `T` (see
+/// e.g., `liberate_late_bound_regions`).
+///
+/// `Decodable` and `Encodable` are implemented for `Binder<T>` using the `impl_binder_encode_decode!` macro.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = "T: Clone"),
+    Copy(bound = "T: Copy"),
+    Hash(bound = "T: Hash"),
+    PartialEq(bound = "T: PartialEq"),
+    Eq(bound = "T: Eq"),
+    Debug(bound = "T: Debug")
+)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub struct Binder<I: Interner, T> {
+    value: T,
+    bound_vars: I::BoundVarKinds,
+}
+
+// FIXME: We manually derive `Lift` because the `derive(Lift_Generic)` doesn't
+// understand how to turn `T` to `T::Lifted` in the output `type Lifted`.
+impl<I: Interner, U: Interner, T> Lift<U> for Binder<I, T>
+where
+    T: Lift<U>,
+    I::BoundVarKinds: Lift<U, Lifted = U::BoundVarKinds>,
+{
+    type Lifted = Binder<U, T::Lifted>;
+
+    fn lift_to_tcx(self, tcx: U) -> Option<Self::Lifted> {
+        Some(Binder {
+            value: self.value.lift_to_tcx(tcx)?,
+            bound_vars: self.bound_vars.lift_to_tcx(tcx)?,
+        })
+    }
+}
+
+macro_rules! impl_binder_encode_decode {
+    ($($t:ty),+ $(,)?) => {
+        $(
+            impl<I: Interner, E: crate::TyEncoder<I = I>> rustc_serialize::Encodable<E> for ty::Binder<I, $t>
+            where
+                $t: rustc_serialize::Encodable<E>,
+                I::BoundVarKinds: rustc_serialize::Encodable<E>,
+            {
+                fn encode(&self, e: &mut E) {
+                    self.bound_vars().encode(e);
+                    self.as_ref().skip_binder().encode(e);
+                }
+            }
+            impl<I: Interner, D: crate::TyDecoder<I = I>> Decodable<D> for ty::Binder<I, $t>
+            where
+                $t: TypeVisitable<I> + rustc_serialize::Decodable<D>,
+                I::BoundVarKinds: rustc_serialize::Decodable<D>,
+            {
+                fn decode(decoder: &mut D) -> Self {
+                    let bound_vars = Decodable::decode(decoder);
+                    ty::Binder::bind_with_vars(<$t>::decode(decoder), bound_vars)
+                }
+            }
+        )*
+    }
+}
+
+impl_binder_encode_decode! {
+    ty::FnSig<I>,
+    ty::TraitPredicate<I>,
+    ty::ExistentialPredicate<I>,
+    ty::TraitRef<I>,
+    ty::ExistentialTraitRef<I>,
+}
+
+impl<I: Interner, T> Binder<I, T>
+where
+    T: TypeVisitable<I>,
+{
+    /// Wraps `value` in a binder, asserting that `value` does not
+    /// contain any bound vars that would be bound by the
+    /// binder. This is commonly used to 'inject' a value T into a
+    /// different binding level.
+    #[track_caller]
+    pub fn dummy(value: T) -> Binder<I, T> {
+        assert!(
+            !value.has_escaping_bound_vars(),
+            "`{value:?}` has escaping bound vars, so it cannot be wrapped in a dummy binder."
+        );
+        Binder { value, bound_vars: Default::default() }
+    }
+
+    pub fn bind_with_vars(value: T, bound_vars: I::BoundVarKinds) -> Binder<I, T> {
+        if cfg!(debug_assertions) {
+            let mut validator = ValidateBoundVars::new(bound_vars);
+            value.visit_with(&mut validator);
+        }
+        Binder { value, bound_vars }
+    }
+}
+
+impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Binder<I, T> {
+    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+        folder.try_fold_binder(self)
+    }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Binder<I, T> {
+    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
+        visitor.visit_binder(self)
+    }
+}
+
+impl<I: Interner, T: TypeFoldable<I>> TypeSuperFoldable<I> for Binder<I, T> {
+    fn try_super_fold_with<F: FallibleTypeFolder<I>>(
+        self,
+        folder: &mut F,
+    ) -> Result<Self, F::Error> {
+        self.try_map_bound(|ty| ty.try_fold_with(folder))
+    }
+}
+
+impl<I: Interner, T: TypeVisitable<I>> TypeSuperVisitable<I> for Binder<I, T> {
+    fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
+        self.as_ref().skip_binder().visit_with(visitor)
+    }
+}
+
+impl<I: Interner, T> Binder<I, T> {
+    /// Skips the binder and returns the "bound" value. This is a
+    /// risky thing to do because it's easy to get confused about
+    /// De Bruijn indices and the like. It is usually better to
+    /// discharge the binder using `no_bound_vars` or
+    /// `instantiate_bound_regions` or something like
+    /// that. `skip_binder` is only valid when you are either
+    /// extracting data that has nothing to do with bound vars, you
+    /// are doing some sort of test that does not involve bound
+    /// regions, or you are being very careful about your depth
+    /// accounting.
+    ///
+    /// Some examples where `skip_binder` is reasonable:
+    ///
+    /// - extracting the `DefId` from a PolyTraitRef;
+    /// - comparing the self type of a PolyTraitRef to see if it is equal to
+    ///   a type parameter `X`, since the type `X` does not reference any regions
+    pub fn skip_binder(self) -> T {
+        self.value
+    }
+
+    pub fn bound_vars(&self) -> I::BoundVarKinds {
+        self.bound_vars
+    }
+
+    pub fn as_ref(&self) -> Binder<I, &T> {
+        Binder { value: &self.value, bound_vars: self.bound_vars }
+    }
+
+    pub fn as_deref(&self) -> Binder<I, &T::Target>
+    where
+        T: Deref,
+    {
+        Binder { value: &self.value, bound_vars: self.bound_vars }
+    }
+
+    pub fn map_bound_ref<F, U: TypeVisitable<I>>(&self, f: F) -> Binder<I, U>
+    where
+        F: FnOnce(&T) -> U,
+    {
+        self.as_ref().map_bound(f)
+    }
+
+    pub fn map_bound<F, U: TypeVisitable<I>>(self, f: F) -> Binder<I, U>
+    where
+        F: FnOnce(T) -> U,
+    {
+        let Binder { value, bound_vars } = self;
+        let value = f(value);
+        if cfg!(debug_assertions) {
+            let mut validator = ValidateBoundVars::new(bound_vars);
+            value.visit_with(&mut validator);
+        }
+        Binder { value, bound_vars }
+    }
+
+    pub fn try_map_bound<F, U: TypeVisitable<I>, E>(self, f: F) -> Result<Binder<I, U>, E>
+    where
+        F: FnOnce(T) -> Result<U, E>,
+    {
+        let Binder { value, bound_vars } = self;
+        let value = f(value)?;
+        if cfg!(debug_assertions) {
+            let mut validator = ValidateBoundVars::new(bound_vars);
+            value.visit_with(&mut validator);
+        }
+        Ok(Binder { value, bound_vars })
+    }
+
+    /// Wraps a `value` in a binder, using the same bound variables as the
+    /// current `Binder`. This should not be used if the new value *changes*
+    /// the bound variables. Note: the (old or new) value itself does not
+    /// necessarily need to *name* all the bound variables.
+    ///
+    /// This currently doesn't do anything different than `bind`, because we
+    /// don't actually track bound vars. However, semantically, it is different
+    /// because bound vars aren't allowed to change here, whereas they are
+    /// in `bind`. This may be (debug) asserted in the future.
+    pub fn rebind<U>(&self, value: U) -> Binder<I, U>
+    where
+        U: TypeVisitable<I>,
+    {
+        Binder::bind_with_vars(value, self.bound_vars)
+    }
+
+    /// Unwraps and returns the value within, but only if it contains
+    /// no bound vars at all. (In other words, if this binder --
+    /// and indeed any enclosing binder -- doesn't bind anything at
+    /// all.) Otherwise, returns `None`.
+    ///
+    /// (One could imagine having a method that just unwraps a single
+    /// binder, but permits late-bound vars bound by enclosing
+    /// binders, but that would require adjusting the debruijn
+    /// indices, and given the shallow binding structure we often use,
+    /// would not be that useful.)
+    pub fn no_bound_vars(self) -> Option<T>
+    where
+        T: TypeVisitable<I>,
+    {
+        // `self.value` is equivalent to `self.skip_binder()`
+        if self.value.has_escaping_bound_vars() { None } else { Some(self.skip_binder()) }
+    }
+
+    /// Splits the contents into two things that share the same binder
+    /// level as the original, returning two distinct binders.
+    ///
+    /// `f` should consider bound regions at depth 1 to be free, and
+    /// anything it produces with bound regions at depth 1 will be
+    /// bound in the resulting return values.
+    pub fn split<U, V, F>(self, f: F) -> (Binder<I, U>, Binder<I, V>)
+    where
+        F: FnOnce(T) -> (U, V),
+    {
+        let Binder { value, bound_vars } = self;
+        let (u, v) = f(value);
+        (Binder { value: u, bound_vars }, Binder { value: v, bound_vars })
+    }
+}
+
+impl<I: Interner, T> Binder<I, Option<T>> {
+    pub fn transpose(self) -> Option<Binder<I, T>> {
+        let Binder { value, bound_vars } = self;
+        value.map(|value| Binder { value, bound_vars })
+    }
+}
+
+impl<I: Interner, T: IntoIterator> Binder<I, T> {
+    pub fn iter(self) -> impl Iterator<Item = Binder<I, T::Item>> {
+        let Binder { value, bound_vars } = self;
+        value.into_iter().map(move |value| Binder { value, bound_vars })
+    }
+}
+
+pub struct ValidateBoundVars<I: Interner> {
+    bound_vars: I::BoundVarKinds,
+    binder_index: ty::DebruijnIndex,
+    // We may encounter the same variable at different levels of binding, so
+    // this can't just be `Ty`
+    visited: SsoHashSet<(ty::DebruijnIndex, I::Ty)>,
+}
+
+impl<I: Interner> ValidateBoundVars<I> {
+    pub fn new(bound_vars: I::BoundVarKinds) -> Self {
+        ValidateBoundVars {
+            bound_vars,
+            binder_index: ty::INNERMOST,
+            visited: SsoHashSet::default(),
+        }
+    }
+}
+
+impl<I: Interner> TypeVisitor<I> for ValidateBoundVars<I> {
+    type Result = ControlFlow<()>;
+
+    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &Binder<I, T>) -> Self::Result {
+        self.binder_index.shift_in(1);
+        let result = t.super_visit_with(self);
+        self.binder_index.shift_out(1);
+        result
+    }
+
+    fn visit_ty(&mut self, t: I::Ty) -> Self::Result {
+        if t.outer_exclusive_binder() < self.binder_index
+            || !self.visited.insert((self.binder_index, t))
+        {
+            return ControlFlow::Break(());
+        }
+        match t.kind() {
+            ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => {
+                let idx = bound_ty.var().as_usize();
+                if self.bound_vars.len() <= idx {
+                    panic!("Not enough bound vars: {:?} not found in {:?}", t, self.bound_vars);
+                }
+                bound_ty.assert_eq(self.bound_vars[idx]);
+            }
+            _ => {}
+        };
+
+        t.super_visit_with(self)
+    }
+
+    fn visit_region(&mut self, r: I::Region) -> Self::Result {
+        match r.kind() {
+            ty::ReBound(index, br) if index == self.binder_index => {
+                let idx = br.var().as_usize();
+                if self.bound_vars.len() <= idx {
+                    panic!("Not enough bound vars: {:?} not found in {:?}", r, self.bound_vars);
+                }
+                br.assert_eq(self.bound_vars[idx]);
+            }
+
+            _ => (),
+        };
+
+        ControlFlow::Continue(())
+    }
 }
diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs
index f041c58..1c30f03 100644
--- a/compiler/rustc_type_ir/src/canonical.rs
+++ b/compiler/rustc_type_ir/src/canonical.rs
@@ -1,19 +1,26 @@
-use rustc_ast_ir::try_visit;
-use rustc_ast_ir::visit::VisitorResult;
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
+use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 use std::fmt;
 use std::hash::Hash;
+use std::ops::Index;
 
-use crate::fold::{FallibleTypeFolder, TypeFoldable};
-use crate::visit::{TypeVisitable, TypeVisitor};
-use crate::{Interner, PlaceholderLike, UniverseIndex};
+use crate::inherent::*;
+use crate::{self as ty, Interner, UniverseIndex};
 
 /// A "canonicalized" type `V` is one where all free inference
 /// variables have been rewritten to "canonical vars". These are
 /// numbered starting from 0 in order of first appearance.
 #[derive(derivative::Derivative)]
-#[derivative(Clone(bound = "V: Clone"), Hash(bound = "V: Hash"))]
+#[derivative(
+    Clone(bound = "V: Clone"),
+    Hash(bound = "V: Hash"),
+    PartialEq(bound = "V: PartialEq"),
+    Eq(bound = "V: Eq"),
+    Debug(bound = "V: fmt::Debug"),
+    Copy(bound = "V: Copy")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub struct Canonical<I: Interner, V> {
     pub value: V,
@@ -63,18 +70,6 @@
     }
 }
 
-impl<I: Interner, V: Eq> Eq for Canonical<I, V> {}
-
-impl<I: Interner, V: PartialEq> PartialEq for Canonical<I, V> {
-    fn eq(&self, other: &Self) -> bool {
-        let Self { value, max_universe, variables, defining_opaque_types } = self;
-        *value == other.value
-            && *max_universe == other.max_universe
-            && *variables == other.variables
-            && *defining_opaque_types == other.defining_opaque_types
-    }
-}
-
 impl<I: Interner, V: fmt::Display> fmt::Display for Canonical<I, V> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         let Self { value, max_universe, variables, defining_opaque_types } = self;
@@ -85,84 +80,25 @@
     }
 }
 
-impl<I: Interner, V: fmt::Debug> fmt::Debug for Canonical<I, V> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let Self { value, max_universe, variables, defining_opaque_types } = self;
-        f.debug_struct("Canonical")
-            .field("value", &value)
-            .field("max_universe", &max_universe)
-            .field("variables", &variables)
-            .field("defining_opaque_types", &defining_opaque_types)
-            .finish()
-    }
-}
-
-impl<I: Interner, V: Copy> Copy for Canonical<I, V> where I::CanonicalVars: Copy {}
-
-impl<I: Interner, V: TypeFoldable<I>> TypeFoldable<I> for Canonical<I, V>
-where
-    I::CanonicalVars: TypeFoldable<I>,
-{
-    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        Ok(Canonical {
-            value: self.value.try_fold_with(folder)?,
-            max_universe: self.max_universe.try_fold_with(folder)?,
-            variables: self.variables.try_fold_with(folder)?,
-            defining_opaque_types: self.defining_opaque_types,
-        })
-    }
-}
-
-impl<I: Interner, V: TypeVisitable<I>> TypeVisitable<I> for Canonical<I, V>
-where
-    I::CanonicalVars: TypeVisitable<I>,
-{
-    fn visit_with<F: TypeVisitor<I>>(&self, folder: &mut F) -> F::Result {
-        let Self { value, max_universe, variables, defining_opaque_types } = self;
-        try_visit!(value.visit_with(folder));
-        try_visit!(max_universe.visit_with(folder));
-        try_visit!(defining_opaque_types.visit_with(folder));
-        variables.visit_with(folder)
-    }
-}
-
 /// Information about a canonical variable that is included with the
 /// canonical value. This is sufficient information for code to create
 /// a copy of the canonical value in some other inference context,
 /// with fresh inference variables replacing the canonical values.
 #[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    Debug(bound = ""),
+    Eq(bound = ""),
+    PartialEq(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub struct CanonicalVarInfo<I: Interner> {
     pub kind: CanonicalVarKind<I>,
 }
 
-impl<I: Interner> PartialEq for CanonicalVarInfo<I> {
-    fn eq(&self, other: &Self) -> bool {
-        self.kind == other.kind
-    }
-}
-
-impl<I: Interner> Eq for CanonicalVarInfo<I> {}
-
-impl<I: Interner> TypeVisitable<I> for CanonicalVarInfo<I>
-where
-    I::Ty: TypeVisitable<I>,
-{
-    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
-        self.kind.visit_with(visitor)
-    }
-}
-
-impl<I: Interner> TypeFoldable<I> for CanonicalVarInfo<I>
-where
-    I::Ty: TypeFoldable<I>,
-{
-    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        Ok(CanonicalVarInfo { kind: self.kind.try_fold_with(folder)? })
-    }
-}
-
 impl<I: Interner> CanonicalVarInfo<I> {
     pub fn universe(self) -> UniverseIndex {
         self.kind.universe()
@@ -215,6 +151,7 @@
 /// that analyzes type-like values.
 #[derive(derivative::Derivative)]
 #[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub enum CanonicalVarKind<I: Interner> {
     /// Some kind of type inference variable.
@@ -257,51 +194,6 @@
     }
 }
 
-impl<I: Interner> Eq for CanonicalVarKind<I> {}
-
-impl<I: Interner> TypeVisitable<I> for CanonicalVarKind<I>
-where
-    I::Ty: TypeVisitable<I>,
-{
-    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
-        match self {
-            CanonicalVarKind::Ty(_)
-            | CanonicalVarKind::PlaceholderTy(_)
-            | CanonicalVarKind::Region(_)
-            | CanonicalVarKind::PlaceholderRegion(_)
-            | CanonicalVarKind::Effect => V::Result::output(),
-            CanonicalVarKind::Const(_, ty) | CanonicalVarKind::PlaceholderConst(_, ty) => {
-                ty.visit_with(visitor)
-            }
-        }
-    }
-}
-
-impl<I: Interner> TypeFoldable<I> for CanonicalVarKind<I>
-where
-    I::Ty: TypeFoldable<I>,
-{
-    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        Ok(match self {
-            CanonicalVarKind::Ty(kind) => CanonicalVarKind::Ty(kind),
-            CanonicalVarKind::Region(kind) => CanonicalVarKind::Region(kind),
-            CanonicalVarKind::Const(kind, ty) => {
-                CanonicalVarKind::Const(kind, ty.try_fold_with(folder)?)
-            }
-            CanonicalVarKind::PlaceholderTy(placeholder) => {
-                CanonicalVarKind::PlaceholderTy(placeholder)
-            }
-            CanonicalVarKind::PlaceholderRegion(placeholder) => {
-                CanonicalVarKind::PlaceholderRegion(placeholder)
-            }
-            CanonicalVarKind::PlaceholderConst(placeholder, ty) => {
-                CanonicalVarKind::PlaceholderConst(placeholder, ty.try_fold_with(folder)?)
-            }
-            CanonicalVarKind::Effect => CanonicalVarKind::Effect,
-        })
-    }
-}
-
 impl<I: Interner> CanonicalVarKind<I> {
     pub fn universe(self) -> UniverseIndex {
         match self {
@@ -354,6 +246,7 @@
 /// usize or f32). In order to faithfully reproduce a type, we need to
 /// know what set of types a given type variable can be unified with.
 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
 pub enum CanonicalTyVarKind {
     /// General type variable `?T` that can be unified with arbitrary types.
@@ -365,3 +258,139 @@
     /// Floating-point type variable `?F` (that can only be unified with float types).
     Float,
 }
+
+/// A set of values corresponding to the canonical variables from some
+/// `Canonical`. You can give these values to
+/// `canonical_value.instantiate` to instantiate them into the canonical
+/// value at the right places.
+///
+/// When you canonicalize a value `V`, you get back one of these
+/// vectors with the original values that were replaced by canonical
+/// variables. You will need to supply it later to instantiate the
+/// canonicalized query response.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Hash(bound = ""),
+    Debug(bound = "")
+)]
+#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+pub struct CanonicalVarValues<I: Interner> {
+    pub var_values: I::GenericArgs,
+}
+
+impl<I: Interner> CanonicalVarValues<I> {
+    pub fn is_identity(&self) -> bool {
+        self.var_values.into_iter().enumerate().all(|(bv, arg)| match arg.kind() {
+            ty::GenericArgKind::Lifetime(r) => {
+                matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if br.var().as_usize() == bv)
+            }
+            ty::GenericArgKind::Type(ty) => {
+                matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if bt.var().as_usize() == bv)
+            }
+            ty::GenericArgKind::Const(ct) => {
+                matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if bc.var().as_usize() == bv)
+            }
+        })
+    }
+
+    pub fn is_identity_modulo_regions(&self) -> bool {
+        let mut var = ty::BoundVar::ZERO;
+        for arg in self.var_values {
+            match arg.kind() {
+                ty::GenericArgKind::Lifetime(r) => {
+                    if matches!(r.kind(), ty::ReBound(ty::INNERMOST, br) if var == br.var()) {
+                        var = var + 1;
+                    } else {
+                        // It's ok if this region var isn't an identity variable
+                    }
+                }
+                ty::GenericArgKind::Type(ty) => {
+                    if matches!(ty.kind(), ty::Bound(ty::INNERMOST, bt) if var == bt.var()) {
+                        var = var + 1;
+                    } else {
+                        return false;
+                    }
+                }
+                ty::GenericArgKind::Const(ct) => {
+                    if matches!(ct.kind(), ty::ConstKind::Bound(ty::INNERMOST, bc) if var == bc.var())
+                    {
+                        var = var + 1;
+                    } else {
+                        return false;
+                    }
+                }
+            }
+        }
+
+        true
+    }
+
+    // Given a list of canonical variables, construct a set of values which are
+    // the identity response.
+    pub fn make_identity(tcx: I, infos: I::CanonicalVars) -> CanonicalVarValues<I> {
+        CanonicalVarValues {
+            var_values: tcx.mk_args_from_iter(infos.into_iter().enumerate().map(
+                |(i, info)| -> I::GenericArg {
+                    match info.kind {
+                        CanonicalVarKind::Ty(_) | CanonicalVarKind::PlaceholderTy(_) => {
+                            Ty::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i))
+                                .into()
+                        }
+                        CanonicalVarKind::Region(_) | CanonicalVarKind::PlaceholderRegion(_) => {
+                            Region::new_anon_bound(tcx, ty::INNERMOST, ty::BoundVar::from_usize(i))
+                                .into()
+                        }
+                        CanonicalVarKind::Effect => Const::new_anon_bound(
+                            tcx,
+                            ty::INNERMOST,
+                            ty::BoundVar::from_usize(i),
+                            Ty::new_bool(tcx),
+                        )
+                        .into(),
+                        CanonicalVarKind::Const(_, ty)
+                        | CanonicalVarKind::PlaceholderConst(_, ty) => Const::new_anon_bound(
+                            tcx,
+                            ty::INNERMOST,
+                            ty::BoundVar::from_usize(i),
+                            ty,
+                        )
+                        .into(),
+                    }
+                },
+            )),
+        }
+    }
+
+    /// Creates dummy var values which should not be used in a
+    /// canonical response.
+    pub fn dummy() -> CanonicalVarValues<I> {
+        CanonicalVarValues { var_values: Default::default() }
+    }
+
+    #[inline]
+    pub fn len(&self) -> usize {
+        self.var_values.len()
+    }
+}
+
+impl<'a, I: Interner> IntoIterator for &'a CanonicalVarValues<I> {
+    type Item = I::GenericArg;
+    type IntoIter = <I::GenericArgs as IntoIterator>::IntoIter;
+
+    fn into_iter(self) -> Self::IntoIter {
+        self.var_values.into_iter()
+    }
+}
+
+impl<I: Interner> Index<ty::BoundVar> for CanonicalVarValues<I> {
+    type Output = I::GenericArg;
+
+    fn index(&self, value: ty::BoundVar) -> &I::GenericArg {
+        &self.var_values[value.as_usize()]
+    }
+}
diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs
index c1506f9..7076df2 100644
--- a/compiler/rustc_type_ir/src/const_kind.rs
+++ b/compiler/rustc_type_ir/src/const_kind.rs
@@ -2,15 +2,16 @@
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 #[cfg(feature = "nightly")]
 use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
+use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 use std::fmt;
 
-use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
+use crate::{self as ty, DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
 
 use self::ConstKind::*;
 
 /// Represents a constant in Rust.
 #[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))]
+#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub enum ConstKind<I: Interner> {
     /// A const generic parameter.
@@ -28,7 +29,7 @@
     /// An unnormalized const item such as an anon const or assoc const or free const item.
     /// Right now anything other than anon consts does not actually work properly but this
     /// should
-    Unevaluated(I::AliasConst),
+    Unevaluated(ty::UnevaluatedConst<I>),
 
     /// Used to hold computed value.
     Value(I::ValueConst),
@@ -58,8 +59,6 @@
     }
 }
 
-impl<I: Interner> Eq for ConstKind<I> {}
-
 impl<I: Interner> fmt::Debug for ConstKind<I> {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         WithInfcx::with_no_infcx(self).fmt(f)
@@ -88,6 +87,46 @@
     }
 }
 
+/// An unevaluated (potentially generic) constant used in the type-system.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct UnevaluatedConst<I: Interner> {
+    pub def: I::DefId,
+    pub args: I::GenericArgs,
+}
+
+impl<I: Interner> UnevaluatedConst<I> {
+    #[inline]
+    pub fn new(def: I::DefId, args: I::GenericArgs) -> UnevaluatedConst<I> {
+        UnevaluatedConst { def, args }
+    }
+}
+
+impl<I: Interner> fmt::Debug for UnevaluatedConst<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        WithInfcx::with_no_infcx(self).fmt(f)
+    }
+}
+impl<I: Interner> DebugWithInfcx<I> for UnevaluatedConst<I> {
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
+        f: &mut core::fmt::Formatter<'_>,
+    ) -> core::fmt::Result {
+        f.debug_struct("UnevaluatedConst")
+            .field("def", &this.data.def)
+            .field("args", &this.wrap(this.data.args))
+            .finish()
+    }
+}
+
 rustc_index::newtype_index! {
     /// A **`const`** **v**ariable **ID**.
     #[encodable]
diff --git a/compiler/rustc_type_ir/src/debug.rs b/compiler/rustc_type_ir/src/debug.rs
index 9298360..4e8be1e 100644
--- a/compiler/rustc_type_ir/src/debug.rs
+++ b/compiler/rustc_type_ir/src/debug.rs
@@ -1,4 +1,6 @@
-use crate::{ConstVid, InferCtxtLike, Interner, TyVid, UniverseIndex};
+use crate::{
+    ConstVid, EffectVid, FloatVid, InferCtxtLike, IntVid, Interner, RegionVid, TyVid, UniverseIndex,
+};
 
 use core::fmt;
 use std::marker::PhantomData;
@@ -16,7 +18,7 @@
         None
     }
 
-    fn universe_of_lt(&self, _lt: I::InferRegion) -> Option<UniverseIndex> {
+    fn universe_of_lt(&self, _lt: RegionVid) -> Option<UniverseIndex> {
         None
     }
 
@@ -24,27 +26,31 @@
         None
     }
 
-    fn root_ty_var(&self, vid: TyVid) -> TyVid {
-        vid
+    fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> I::Ty {
+        panic!("cannot resolve {vid:?}")
     }
 
-    fn probe_ty_var(&self, _vid: TyVid) -> Option<I::Ty> {
-        None
+    fn opportunistic_resolve_int_var(&self, vid: IntVid) -> I::Ty {
+        panic!("cannot resolve {vid:?}")
     }
 
-    fn opportunistic_resolve_lt_var(&self, _vid: I::InferRegion) -> Option<I::Region> {
-        None
+    fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> I::Ty {
+        panic!("cannot resolve {vid:?}")
     }
 
-    fn root_ct_var(&self, vid: ConstVid) -> ConstVid {
-        vid
+    fn opportunistic_resolve_ct_var(&self, vid: ConstVid, _: I::Ty) -> I::Const {
+        panic!("cannot resolve {vid:?}")
     }
 
-    fn probe_ct_var(&self, _vid: ConstVid) -> Option<I::Const> {
-        None
+    fn opportunistic_resolve_effect_var(&self, vid: EffectVid, _: I::Ty) -> I::Const {
+        panic!("cannot resolve {vid:?}")
     }
 
-    fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes {
+    fn opportunistic_resolve_lt_var(&self, vid: crate::RegionVid) -> I::Region {
+        panic!("cannot resolve {vid:?}")
+    }
+
+    fn defining_opaque_types(&self) -> I::DefiningOpaqueTypes {
         Default::default()
     }
 }
diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs
index 01bb3d7..405aba3 100644
--- a/compiler/rustc_type_ir/src/fold.rs
+++ b/compiler/rustc_type_ir/src/fold.rs
@@ -48,8 +48,8 @@
 use rustc_index::{Idx, IndexVec};
 use std::mem;
 
-use crate::Lrc;
-use crate::{visit::TypeVisitable, Interner};
+use crate::visit::TypeVisitable;
+use crate::{self as ty, Interner, Lrc};
 
 #[cfg(feature = "nightly")]
 type Never = !;
@@ -128,10 +128,9 @@
 pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = Never> {
     fn interner(&self) -> I;
 
-    fn fold_binder<T>(&mut self, t: I::Binder<T>) -> I::Binder<T>
+    fn fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> ty::Binder<I, T>
     where
         T: TypeFoldable<I>,
-        I::Binder<T>: TypeSuperFoldable<I>,
     {
         t.super_fold_with(self)
     }
@@ -167,10 +166,9 @@
 
     fn interner(&self) -> I;
 
-    fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, Self::Error>
+    fn try_fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> Result<ty::Binder<I, T>, Self::Error>
     where
         T: TypeFoldable<I>,
-        I::Binder<T>: TypeSuperFoldable<I>,
     {
         t.try_super_fold_with(self)
     }
@@ -206,10 +204,9 @@
         TypeFolder::interner(self)
     }
 
-    fn try_fold_binder<T>(&mut self, t: I::Binder<T>) -> Result<I::Binder<T>, Never>
+    fn try_fold_binder<T>(&mut self, t: ty::Binder<I, T>) -> Result<ty::Binder<I, T>, Never>
     where
         T: TypeFoldable<I>,
-        I::Binder<T>: TypeSuperFoldable<I>,
     {
         Ok(self.fold_binder(t))
     }
diff --git a/compiler/rustc_type_ir/src/generic_arg.rs b/compiler/rustc_type_ir/src/generic_arg.rs
new file mode 100644
index 0000000..cc8c444
--- /dev/null
+++ b/compiler/rustc_type_ir/src/generic_arg.rs
@@ -0,0 +1,32 @@
+use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
+
+use crate::Interner;
+
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Debug(bound = ""),
+    Eq(bound = ""),
+    PartialEq(bound = "")
+)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub enum GenericArgKind<I: Interner> {
+    Lifetime(I::Region),
+    Type(I::Ty),
+    Const(I::Const),
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Debug(bound = ""),
+    Eq(bound = ""),
+    PartialEq(bound = "")
+)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub enum TermKind<I: Interner> {
+    Ty(I::Ty),
+    Const(I::Const),
+}
diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs
index a53287c..bb5081f 100644
--- a/compiler/rustc_type_ir/src/infcx.rs
+++ b/compiler/rustc_type_ir/src/infcx.rs
@@ -1,4 +1,4 @@
-use crate::{ConstVid, Interner, TyVid, UniverseIndex};
+use crate::{ConstVid, EffectVid, FloatVid, IntVid, Interner, RegionVid, TyVid, UniverseIndex};
 
 pub trait InferCtxtLike {
     type Interner: Interner;
@@ -6,37 +6,23 @@
     fn interner(&self) -> Self::Interner;
 
     fn universe_of_ty(&self, ty: TyVid) -> Option<UniverseIndex>;
-
-    /// Resolve `TyVid` to its root `TyVid`.
-    fn root_ty_var(&self, vid: TyVid) -> TyVid;
-
-    /// Resolve `TyVid` to its inferred type, if it has been equated with a non-infer type.
-    fn probe_ty_var(&self, vid: TyVid) -> Option<<Self::Interner as Interner>::Ty>;
-
-    fn universe_of_lt(
-        &self,
-        lt: <Self::Interner as Interner>::InferRegion,
-    ) -> Option<UniverseIndex>;
-
-    /// Resolve `InferRegion` to its inferred region, if it has been equated with
-    /// a non-infer region.
-    ///
-    /// FIXME: This has slightly different semantics than `{probe,resolve}_{ty,ct}_var`,
-    /// that has to do with the fact unlike `Ty` or `Const` vars, in rustc, we may
-    /// not always be able to *name* the root region var from the universe of the
-    /// var we're trying to resolve. That's why it's called *opportunistic*.
-    fn opportunistic_resolve_lt_var(
-        &self,
-        vid: <Self::Interner as Interner>::InferRegion,
-    ) -> Option<<Self::Interner as Interner>::Region>;
-
+    fn universe_of_lt(&self, lt: RegionVid) -> Option<UniverseIndex>;
     fn universe_of_ct(&self, ct: ConstVid) -> Option<UniverseIndex>;
 
-    /// Resolve `ConstVid` to its root `ConstVid`.
-    fn root_ct_var(&self, vid: ConstVid) -> ConstVid;
-
-    /// Resolve `ConstVid` to its inferred type, if it has been equated with a non-infer type.
-    fn probe_ct_var(&self, vid: ConstVid) -> Option<<Self::Interner as Interner>::Const>;
+    fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> <Self::Interner as Interner>::Ty;
+    fn opportunistic_resolve_int_var(&self, vid: IntVid) -> <Self::Interner as Interner>::Ty;
+    fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> <Self::Interner as Interner>::Ty;
+    fn opportunistic_resolve_ct_var(
+        &self,
+        vid: ConstVid,
+        ty: <Self::Interner as Interner>::Ty,
+    ) -> <Self::Interner as Interner>::Const;
+    fn opportunistic_resolve_effect_var(
+        &self,
+        vid: EffectVid,
+        ty: <Self::Interner as Interner>::Ty,
+    ) -> <Self::Interner as Interner>::Const;
+    fn opportunistic_resolve_lt_var(&self, vid: RegionVid) -> <Self::Interner as Interner>::Region;
 
     fn defining_opaque_types(&self) -> <Self::Interner as Interner>::DefiningOpaqueTypes;
 }
diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs
new file mode 100644
index 0000000..77fe30a
--- /dev/null
+++ b/compiler/rustc_type_ir/src/inherent.rs
@@ -0,0 +1,164 @@
+//! Set of traits which are used to emulate the inherent impls that are present in `rustc_middle`.
+//! It is customary to glob-import `rustc_type_ir::inherent::*` to bring all of these traits into
+//! scope when programming in interner-agnostic settings, and to avoid importing any of these
+//! directly elsewhere (i.e. specify the full path for an implementation downstream).
+
+use std::fmt::Debug;
+use std::hash::Hash;
+use std::ops::Deref;
+
+use crate::fold::{TypeFoldable, TypeSuperFoldable};
+use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
+use crate::{self as ty, DebugWithInfcx, Interner, UpcastFrom};
+
+pub trait Ty<I: Interner<Ty = Self>>:
+    Copy
+    + DebugWithInfcx<I>
+    + Hash
+    + Eq
+    + Into<I::GenericArg>
+    + Into<I::Term>
+    + IntoKind<Kind = ty::TyKind<I>>
+    + TypeSuperVisitable<I>
+    + TypeSuperFoldable<I>
+    + Flags
+{
+    fn new_bool(interner: I) -> Self;
+
+    fn new_infer(interner: I, var: ty::InferTy) -> Self;
+
+    fn new_var(interner: I, var: ty::TyVid) -> Self;
+
+    fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
+
+    fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy<I>) -> Self;
+}
+
+pub trait Tys<I: Interner<Tys = Self>>:
+    Copy
+    + Debug
+    + Hash
+    + Eq
+    + IntoIterator<Item = I::Ty>
+    + Deref<Target: Deref<Target = [I::Ty]>>
+    + TypeVisitable<I>
+{
+    fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty);
+}
+
+pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq {
+    /// Whether this ABI is `extern "Rust"`.
+    fn is_rust(self) -> bool;
+}
+
+pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq {
+    fn is_safe(self) -> bool;
+
+    fn prefix_str(self) -> &'static str;
+}
+
+pub trait Region<I: Interner<Region = Self>>:
+    Copy
+    + DebugWithInfcx<I>
+    + Hash
+    + Eq
+    + Into<I::GenericArg>
+    + IntoKind<Kind = ty::RegionKind<I>>
+    + Flags
+{
+    fn new_anon_bound(interner: I, debruijn: ty::DebruijnIndex, var: ty::BoundVar) -> Self;
+
+    fn new_static(interner: I) -> Self;
+}
+
+pub trait Const<I: Interner<Const = Self>>:
+    Copy
+    + DebugWithInfcx<I>
+    + Hash
+    + Eq
+    + Into<I::GenericArg>
+    + Into<I::Term>
+    + IntoKind<Kind = ty::ConstKind<I>>
+    + TypeSuperVisitable<I>
+    + TypeSuperFoldable<I>
+    + Flags
+{
+    fn new_infer(interner: I, var: ty::InferConst, ty: I::Ty) -> Self;
+
+    fn new_var(interner: I, var: ty::ConstVid, ty: I::Ty) -> Self;
+
+    fn new_anon_bound(
+        interner: I,
+        debruijn: ty::DebruijnIndex,
+        var: ty::BoundVar,
+        ty: I::Ty,
+    ) -> Self;
+
+    fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst<I>, ty: I::Ty) -> Self;
+
+    fn ty(self) -> I::Ty;
+}
+
+pub trait GenericsOf<I: Interner<GenericsOf = Self>> {
+    fn count(&self) -> usize;
+}
+
+pub trait GenericArgs<I: Interner<GenericArgs = Self>>:
+    Copy
+    + DebugWithInfcx<I>
+    + Hash
+    + Eq
+    + IntoIterator<Item = I::GenericArg>
+    + Deref<Target: Deref<Target = [I::GenericArg]>>
+    + Default
+    + TypeFoldable<I>
+{
+    fn type_at(self, i: usize) -> I::Ty;
+
+    fn identity_for_item(interner: I, def_id: I::DefId) -> I::GenericArgs;
+
+    fn extend_with_error(
+        tcx: I,
+        def_id: I::DefId,
+        original_args: &[I::GenericArg],
+    ) -> I::GenericArgs;
+}
+
+pub trait Predicate<I: Interner<Predicate = Self>>:
+    Copy + Debug + Hash + Eq + TypeSuperVisitable<I> + TypeSuperFoldable<I> + Flags
+{
+    fn is_coinductive(self, interner: I) -> bool;
+}
+
+pub trait Clause<I: Interner<Clause = Self>>:
+    Copy
+    + Debug
+    + Hash
+    + Eq
+    // FIXME: Remove these, uplift the `Upcast` impls.
+    + UpcastFrom<I, ty::Binder<I, ty::TraitRef<I>>>
+    + UpcastFrom<I, ty::Binder<I, ty::ProjectionPredicate<I>>>
+{
+}
+
+/// Common capabilities of placeholder kinds
+pub trait PlaceholderLike: Copy + Debug + Hash + Eq {
+    fn universe(self) -> ty::UniverseIndex;
+    fn var(self) -> ty::BoundVar;
+
+    fn with_updated_universe(self, ui: ty::UniverseIndex) -> Self;
+
+    fn new(ui: ty::UniverseIndex, var: ty::BoundVar) -> Self;
+}
+
+pub trait IntoKind {
+    type Kind;
+
+    fn kind(self) -> Self::Kind;
+}
+
+pub trait BoundVarLike<I: Interner> {
+    fn var(self) -> ty::BoundVar;
+
+    fn assert_eq(self, var: I::BoundVarKind);
+}
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 70f7e58..9b8bb21 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -1,49 +1,69 @@
 use smallvec::SmallVec;
 use std::fmt::Debug;
 use std::hash::Hash;
+use std::ops::Deref;
 
-use crate::fold::TypeSuperFoldable;
+use crate::inherent::*;
+use crate::ir_print::IrPrint;
+use crate::solve::inspect::GoalEvaluationStep;
 use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable};
 use crate::{
-    new, BoundVar, BoundVars, CanonicalVarInfo, ConstKind, DebugWithInfcx, RegionKind, TyKind,
-    UniverseIndex,
+    AliasTerm, AliasTermKind, AliasTy, AliasTyKind, CanonicalVarInfo, CoercePredicate,
+    DebugWithInfcx, ExistentialProjection, ExistentialTraitRef, FnSig, GenericArgKind,
+    NormalizesTo, ProjectionPredicate, SubtypePredicate, TermKind, TraitPredicate, TraitRef,
 };
 
-pub trait Interner: Sized + Copy {
-    type DefId: Copy + Debug + Hash + Eq;
-    type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>;
+pub trait Interner:
+    Sized
+    + Copy
+    + IrPrint<AliasTy<Self>>
+    + IrPrint<AliasTerm<Self>>
+    + IrPrint<TraitRef<Self>>
+    + IrPrint<TraitPredicate<Self>>
+    + IrPrint<ExistentialTraitRef<Self>>
+    + IrPrint<ExistentialProjection<Self>>
+    + IrPrint<ProjectionPredicate<Self>>
+    + IrPrint<NormalizesTo<Self>>
+    + IrPrint<SubtypePredicate<Self>>
+    + IrPrint<CoercePredicate<Self>>
+    + IrPrint<FnSig<Self>>
+{
+    type DefId: Copy + Debug + Hash + Eq + TypeVisitable<Self>;
     type AdtDef: Copy + Debug + Hash + Eq;
 
-    type GenericArgs: Copy
+    type GenericArgs: GenericArgs<Self>;
+    /// The slice of args for a specific item. For a GAT like `type Foo<'a>`, it will be `['a]`,
+    /// not including the args from the parent item (trait or impl).
+    type OwnItemArgs: Copy + Debug + Hash + Eq;
+    type GenericArg: Copy
         + DebugWithInfcx<Self>
         + Hash
         + Eq
-        + IntoIterator<Item = Self::GenericArg>;
-    type GenericArg: Copy + DebugWithInfcx<Self> + Hash + Eq;
-    type Term: Copy + Debug + Hash + Eq;
+        + IntoKind<Kind = GenericArgKind<Self>>
+        + TypeVisitable<Self>;
+    type Term: Copy + Debug + Hash + Eq + IntoKind<Kind = TermKind<Self>> + TypeVisitable<Self>;
 
-    type Binder<T: TypeVisitable<Self>>: BoundVars<Self> + TypeSuperVisitable<Self>;
-    type BoundVars: IntoIterator<Item = Self::BoundVar>;
-    type BoundVar;
+    type BoundVarKinds: Copy
+        + Debug
+        + Hash
+        + Eq
+        + Deref<Target: Deref<Target = [Self::BoundVarKind]>>
+        + Default;
+    type BoundVarKind: Copy + Debug + Hash + Eq;
 
     type CanonicalVars: Copy + Debug + Hash + Eq + IntoIterator<Item = CanonicalVarInfo<Self>>;
+    type PredefinedOpaques: Copy + Debug + Hash + Eq;
+    type DefiningOpaqueTypes: Copy + Debug + Hash + Default + Eq + TypeVisitable<Self>;
+    type ExternalConstraints: Copy + Debug + Hash + Eq;
+    type GoalEvaluationSteps: Copy + Debug + Hash + Eq + Deref<Target = [GoalEvaluationStep<Self>]>;
 
     // Kinds of tys
-    type Ty: Copy
-        + DebugWithInfcx<Self>
-        + Hash
-        + Eq
-        + Into<Self::GenericArg>
-        + IntoKind<Kind = TyKind<Self>>
-        + TypeSuperVisitable<Self>
-        + TypeSuperFoldable<Self>
-        + Flags
-        + new::Ty<Self>;
-    type Tys: Copy + Debug + Hash + Eq + IntoIterator<Item = Self::Ty>;
-    type AliasTy: Copy + DebugWithInfcx<Self> + Hash + Eq;
+    type Ty: Ty<Self>;
+    type Tys: Tys<Self>;
+    type FnInputTys: Copy + Debug + Hash + Eq + Deref<Target = [Self::Ty]> + TypeVisitable<Self>;
     type ParamTy: Copy + Debug + Hash + Eq;
-    type BoundTy: Copy + Debug + Hash + Eq;
-    type PlaceholderTy: Copy + Debug + Hash + Eq + PlaceholderLike;
+    type BoundTy: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
+    type PlaceholderTy: PlaceholderLike;
 
     // Things stored inside of tys
     type ErrorGuaranteed: Copy + Debug + Hash + Eq;
@@ -51,80 +71,61 @@
     type PolyFnSig: Copy + DebugWithInfcx<Self> + Hash + Eq;
     type AllocId: Copy + Debug + Hash + Eq;
     type Pat: Copy + Debug + Hash + Eq + DebugWithInfcx<Self>;
+    type Safety: Safety<Self>;
+    type Abi: Abi<Self>;
 
     // Kinds of consts
-    type Const: Copy
-        + DebugWithInfcx<Self>
-        + Hash
-        + Eq
-        + Into<Self::GenericArg>
-        + IntoKind<Kind = ConstKind<Self>>
-        + ConstTy<Self>
-        + TypeSuperVisitable<Self>
-        + TypeSuperFoldable<Self>
-        + Flags
-        + new::Const<Self>;
-    type AliasConst: Copy + DebugWithInfcx<Self> + Hash + Eq;
-    type PlaceholderConst: Copy + Debug + Hash + Eq + PlaceholderLike;
+    type Const: Const<Self>;
+    type PlaceholderConst: PlaceholderLike;
     type ParamConst: Copy + Debug + Hash + Eq;
-    type BoundConst: Copy + Debug + Hash + Eq;
+    type BoundConst: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
     type ValueConst: Copy + Debug + Hash + Eq;
     type ExprConst: Copy + DebugWithInfcx<Self> + Hash + Eq;
 
     // Kinds of regions
-    type Region: Copy
-        + DebugWithInfcx<Self>
-        + Hash
-        + Eq
-        + Into<Self::GenericArg>
-        + IntoKind<Kind = RegionKind<Self>>
-        + Flags
-        + new::Region<Self>;
+    type Region: Region<Self>;
     type EarlyParamRegion: Copy + Debug + Hash + Eq;
     type LateParamRegion: Copy + Debug + Hash + Eq;
-    type BoundRegion: Copy + Debug + Hash + Eq;
-    type InferRegion: Copy + DebugWithInfcx<Self> + Hash + Eq;
-    type PlaceholderRegion: Copy + Debug + Hash + Eq + PlaceholderLike;
+    type BoundRegion: Copy + Debug + Hash + Eq + BoundVarLike<Self>;
+    type PlaceholderRegion: PlaceholderLike;
 
     // Predicates
-    type Predicate: Copy
-        + Debug
-        + Hash
-        + Eq
-        + TypeSuperVisitable<Self>
-        + TypeSuperFoldable<Self>
-        + Flags;
-    type TraitPredicate: Copy + Debug + Hash + Eq;
-    type RegionOutlivesPredicate: Copy + Debug + Hash + Eq;
-    type TypeOutlivesPredicate: Copy + Debug + Hash + Eq;
-    type ProjectionPredicate: Copy + Debug + Hash + Eq;
-    type NormalizesTo: Copy + Debug + Hash + Eq;
-    type SubtypePredicate: Copy + Debug + Hash + Eq;
-    type CoercePredicate: Copy + Debug + Hash + Eq;
-    type ClosureKind: Copy + Debug + Hash + Eq;
+    type ParamEnv: Copy + Debug + Hash + Eq;
+    type Predicate: Predicate<Self>;
+    type Clause: Clause<Self>;
     type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags;
 
     fn mk_canonical_var_infos(self, infos: &[CanonicalVarInfo<Self>]) -> Self::CanonicalVars;
-}
 
-/// Common capabilities of placeholder kinds
-pub trait PlaceholderLike {
-    fn universe(self) -> UniverseIndex;
-    fn var(self) -> BoundVar;
+    type GenericsOf: GenericsOf<Self>;
+    fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf;
 
-    fn with_updated_universe(self, ui: UniverseIndex) -> Self;
+    // FIXME: Remove after uplifting `EarlyBinder`
+    fn type_of_instantiated(self, def_id: Self::DefId, args: Self::GenericArgs) -> Self::Ty;
 
-    fn new(ui: UniverseIndex, var: BoundVar) -> Self;
-}
+    fn alias_ty_kind(self, alias: AliasTy<Self>) -> AliasTyKind;
 
-pub trait IntoKind {
-    type Kind;
+    fn alias_term_kind(self, alias: AliasTerm<Self>) -> AliasTermKind;
 
-    fn kind(self) -> Self::Kind;
-}
+    fn trait_ref_and_own_args_for_alias(
+        self,
+        def_id: Self::DefId,
+        args: Self::GenericArgs,
+    ) -> (TraitRef<Self>, Self::OwnItemArgs);
 
-pub trait ConstTy<I: Interner> {
-    fn ty(self) -> I::Ty;
+    fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs;
+
+    fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs;
+
+    fn check_and_mk_args(
+        self,
+        def_id: Self::DefId,
+        args: impl IntoIterator<Item: Into<Self::GenericArg>>,
+    ) -> Self::GenericArgs;
+
+    fn parent(self, def_id: Self::DefId) -> Self::DefId;
+
+    fn recursion_limit(self) -> usize;
 }
 
 /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter`
diff --git a/compiler/rustc_type_ir/src/ir_print.rs b/compiler/rustc_type_ir/src/ir_print.rs
new file mode 100644
index 0000000..d57d081
--- /dev/null
+++ b/compiler/rustc_type_ir/src/ir_print.rs
@@ -0,0 +1,70 @@
+use std::fmt;
+
+use crate::{
+    AliasTerm, AliasTy, Binder, CoercePredicate, ExistentialProjection, ExistentialTraitRef, FnSig,
+    Interner, NormalizesTo, OutlivesPredicate, ProjectionPredicate, SubtypePredicate,
+    TraitPredicate, TraitRef,
+};
+
+pub trait IrPrint<T> {
+    fn print(t: &T, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
+    fn print_debug(t: &T, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
+}
+
+macro_rules! define_display_via_print {
+    ($($ty:ident),+ $(,)?) => {
+        $(
+            impl<I: Interner> fmt::Display for $ty<I> {
+                fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                    <I as IrPrint<$ty<I>>>::print(self, fmt)
+                }
+            }
+        )*
+    }
+}
+
+impl<I: Interner, T> fmt::Display for Binder<I, T>
+where
+    I: IrPrint<Binder<I, T>>,
+{
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        <I as IrPrint<Binder<I, T>>>::print(self, fmt)
+    }
+}
+
+macro_rules! define_debug_via_print {
+    ($($ty:ident),+ $(,)?) => {
+        $(
+            impl<I: Interner> fmt::Debug for $ty<I> {
+                fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+                    <I as IrPrint<$ty<I>>>::print_debug(self, fmt)
+                }
+            }
+        )*
+    }
+}
+
+define_display_via_print!(
+    TraitRef,
+    TraitPredicate,
+    ExistentialTraitRef,
+    ExistentialProjection,
+    ProjectionPredicate,
+    NormalizesTo,
+    SubtypePredicate,
+    CoercePredicate,
+    AliasTy,
+    AliasTerm,
+    FnSig,
+);
+
+define_debug_via_print!(TraitRef, ExistentialTraitRef, ExistentialProjection);
+
+impl<I: Interner, T> fmt::Display for OutlivesPredicate<I, T>
+where
+    I: IrPrint<OutlivesPredicate<I, T>>,
+{
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        <I as IrPrint<OutlivesPredicate<I, T>>>::print(self, fmt)
+    }
+}
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index ef7437c..4a461b5 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -9,9 +9,13 @@
 extern crate self as rustc_type_ir;
 
 #[cfg(feature = "nightly")]
+use rustc_data_structures::sso::SsoHashSet;
+#[cfg(feature = "nightly")]
 use rustc_data_structures::sync::Lrc;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable, Encodable, HashStable_NoContext};
+#[cfg(not(feature = "nightly"))]
+use std::collections::HashSet as SsoHashSet;
 use std::fmt;
 use std::hash::Hash;
 #[cfg(not(feature = "nightly"))]
@@ -19,11 +23,13 @@
 
 #[macro_use]
 pub mod visit;
-
 #[cfg(feature = "nightly")]
 pub mod codec;
 pub mod fold;
-pub mod new;
+pub mod inherent;
+pub mod ir_print;
+pub mod lift;
+pub mod solve;
 pub mod ty_info;
 pub mod ty_kind;
 
@@ -34,10 +40,13 @@
 mod const_kind;
 mod debug;
 mod flags;
+mod generic_arg;
 mod infcx;
 mod interner;
+mod predicate;
 mod predicate_kind;
 mod region_kind;
+mod upcast;
 
 pub use binder::*;
 pub use canonical::*;
@@ -46,13 +55,16 @@
 pub use const_kind::*;
 pub use debug::{DebugWithInfcx, WithInfcx};
 pub use flags::*;
+pub use generic_arg::*;
 pub use infcx::InferCtxtLike;
 pub use interner::*;
+pub use predicate::*;
 pub use predicate_kind::*;
 pub use region_kind::*;
 pub use ty_info::*;
 pub use ty_kind::*;
-pub use AliasKind::*;
+pub use upcast::*;
+pub use AliasTyKind::*;
 pub use DynKind::*;
 pub use InferTy::*;
 pub use RegionKind::*;
@@ -364,6 +376,16 @@
     pub struct BoundVar {}
 }
 
+impl<I: Interner> inherent::BoundVarLike<I> for BoundVar {
+    fn var(self) -> BoundVar {
+        self
+    }
+
+    fn assert_eq(self, _var: I::BoundVarKind) {
+        unreachable!("FIXME: We really should have a separate `BoundConst` for consts")
+    }
+}
+
 /// Represents the various closure traits in the language. This
 /// will determine the type of the environment (`self`, in the
 /// desugaring) argument that the closure expects.
diff --git a/compiler/rustc_type_ir/src/lift.rs b/compiler/rustc_type_ir/src/lift.rs
new file mode 100644
index 0000000..839da10
--- /dev/null
+++ b/compiler/rustc_type_ir/src/lift.rs
@@ -0,0 +1,21 @@
+/// A trait implemented for all `X<'a>` types that can be safely and
+/// efficiently converted to `X<'tcx>` as long as they are part of the
+/// provided `TyCtxt<'tcx>`.
+/// This can be done, for example, for `Ty<'tcx>` or `GenericArgsRef<'tcx>`
+/// by looking them up in their respective interners.
+///
+/// However, this is still not the best implementation as it does
+/// need to compare the components, even for interned values.
+/// It would be more efficient if `TypedArena` provided a way to
+/// determine whether the address is in the allocated range.
+///
+/// `None` is returned if the value or one of the components is not part
+/// of the provided context.
+/// For `Ty`, `None` can be returned if either the type interner doesn't
+/// contain the `TyKind` key or if the address of the interned
+/// pointer differs. The latter case is possible if a primitive type,
+/// e.g., `()` or `u8`, was interned in a different context.
+pub trait Lift<I>: std::fmt::Debug {
+    type Lifted: std::fmt::Debug;
+    fn lift_to_tcx(self, tcx: I) -> Option<Self::Lifted>;
+}
diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs
index 7dcc885..f2f7b16 100644
--- a/compiler/rustc_type_ir/src/macros.rs
+++ b/compiler/rustc_type_ir/src/macros.rs
@@ -53,4 +53,5 @@
     crate::UniverseIndex,
     rustc_ast_ir::Mutability,
     rustc_ast_ir::Movability,
+    crate::PredicatePolarity,
 }
diff --git a/compiler/rustc_type_ir/src/new.rs b/compiler/rustc_type_ir/src/new.rs
deleted file mode 100644
index 1572a64..0000000
--- a/compiler/rustc_type_ir/src/new.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-use crate::{BoundVar, DebruijnIndex, Interner};
-
-pub trait Ty<I: Interner<Ty = Self>> {
-    fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
-}
-
-pub trait Region<I: Interner<Region = Self>> {
-    fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar) -> Self;
-
-    fn new_static(interner: I) -> Self;
-}
-
-pub trait Const<I: Interner<Const = Self>> {
-    fn new_anon_bound(interner: I, debruijn: DebruijnIndex, var: BoundVar, ty: I::Ty) -> Self;
-}
diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs
new file mode 100644
index 0000000..4e12c6b
--- /dev/null
+++ b/compiler/rustc_type_ir/src/predicate.rs
@@ -0,0 +1,796 @@
+use std::fmt;
+use std::hash::Hash;
+
+#[cfg(feature = "nightly")]
+use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
+use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
+
+use crate::inherent::*;
+use crate::lift::Lift;
+use crate::upcast::Upcast;
+use crate::visit::TypeVisitableExt as _;
+use crate::{self as ty, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
+
+/// `A: 'region`
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = "A: Clone"),
+    Copy(bound = "A: Copy"),
+    Hash(bound = "A: Hash"),
+    PartialEq(bound = "A: PartialEq"),
+    Eq(bound = "A: Eq"),
+    Debug(bound = "A: fmt::Debug")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct OutlivesPredicate<I: Interner, A>(pub A, pub I::Region);
+
+// FIXME: We manually derive `Lift` because the `derive(Lift_Generic)` doesn't
+// understand how to turn `A` to `A::Lifted` in the output `type Lifted`.
+impl<I: Interner, U: Interner, A> Lift<U> for OutlivesPredicate<I, A>
+where
+    A: Lift<U>,
+    I::Region: Lift<U, Lifted = U::Region>,
+{
+    type Lifted = OutlivesPredicate<U, A::Lifted>;
+
+    fn lift_to_tcx(self, tcx: U) -> Option<Self::Lifted> {
+        Some(OutlivesPredicate(self.0.lift_to_tcx(tcx)?, self.1.lift_to_tcx(tcx)?))
+    }
+}
+
+/// A complete reference to a trait. These take numerous guises in syntax,
+/// but perhaps the most recognizable form is in a where-clause:
+/// ```ignore (illustrative)
+/// T: Foo<U>
+/// ```
+/// This would be represented by a trait-reference where the `DefId` is the
+/// `DefId` for the trait `Foo` and the args define `T` as parameter 0,
+/// and `U` as parameter 1.
+///
+/// Trait references also appear in object types like `Foo<U>`, but in
+/// that case the `Self` parameter is absent from the generic parameters.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct TraitRef<I: Interner> {
+    pub def_id: I::DefId,
+    pub args: I::GenericArgs,
+    /// This field exists to prevent the creation of `TraitRef` without
+    /// calling [`TraitRef::new`].
+    _use_trait_ref_new_instead: (),
+}
+
+impl<I: Interner> TraitRef<I> {
+    pub fn new(
+        interner: I,
+        trait_def_id: I::DefId,
+        args: impl IntoIterator<Item: Into<I::GenericArg>>,
+    ) -> Self {
+        let args = interner.check_and_mk_args(trait_def_id, args);
+        Self { def_id: trait_def_id, args, _use_trait_ref_new_instead: () }
+    }
+
+    pub fn from_method(interner: I, trait_id: I::DefId, args: I::GenericArgs) -> TraitRef<I> {
+        let generics = interner.generics_of(trait_id);
+        TraitRef::new(interner, trait_id, args.into_iter().take(generics.count()))
+    }
+
+    /// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`
+    /// are the parameters defined on trait.
+    pub fn identity(interner: I, def_id: I::DefId) -> TraitRef<I> {
+        TraitRef::new(interner, def_id, I::GenericArgs::identity_for_item(interner, def_id))
+    }
+
+    pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
+        TraitRef::new(
+            interner,
+            self.def_id,
+            [self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)),
+        )
+    }
+
+    #[inline]
+    pub fn self_ty(&self) -> I::Ty {
+        self.args.type_at(0)
+    }
+}
+
+impl<I: Interner> ty::Binder<I, TraitRef<I>> {
+    pub fn self_ty(&self) -> ty::Binder<I, I::Ty> {
+        self.map_bound_ref(|tr| tr.self_ty())
+    }
+
+    pub fn def_id(&self) -> I::DefId {
+        self.skip_binder().def_id
+    }
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct TraitPredicate<I: Interner> {
+    pub trait_ref: TraitRef<I>,
+
+    /// If polarity is Positive: we are proving that the trait is implemented.
+    ///
+    /// If polarity is Negative: we are proving that a negative impl of this trait
+    /// exists. (Note that coherence also checks whether negative impls of supertraits
+    /// exist via a series of predicates.)
+    ///
+    /// If polarity is Reserved: that's a bug.
+    pub polarity: PredicatePolarity,
+}
+
+impl<I: Interner> TraitPredicate<I> {
+    pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
+        Self { trait_ref: self.trait_ref.with_self_ty(interner, self_ty), polarity: self.polarity }
+    }
+
+    pub fn def_id(self) -> I::DefId {
+        self.trait_ref.def_id
+    }
+
+    pub fn self_ty(self) -> I::Ty {
+        self.trait_ref.self_ty()
+    }
+}
+
+impl<I: Interner> ty::Binder<I, TraitPredicate<I>> {
+    pub fn def_id(self) -> I::DefId {
+        // Ok to skip binder since trait `DefId` does not care about regions.
+        self.skip_binder().def_id()
+    }
+
+    pub fn self_ty(self) -> ty::Binder<I, I::Ty> {
+        self.map_bound(|trait_ref| trait_ref.self_ty())
+    }
+
+    #[inline]
+    pub fn polarity(self) -> PredicatePolarity {
+        self.skip_binder().polarity
+    }
+}
+
+impl<I: Interner> fmt::Debug for TraitPredicate<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // FIXME(effects) printing?
+        write!(f, "TraitPredicate({:?}, polarity:{:?})", self.trait_ref, self.polarity)
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub enum ImplPolarity {
+    /// `impl Trait for Type`
+    Positive,
+    /// `impl !Trait for Type`
+    Negative,
+    /// `#[rustc_reservation_impl] impl Trait for Type`
+    ///
+    /// This is a "stability hack", not a real Rust feature.
+    /// See #64631 for details.
+    Reservation,
+}
+
+impl fmt::Display for ImplPolarity {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Positive => f.write_str("positive"),
+            Self::Negative => f.write_str("negative"),
+            Self::Reservation => f.write_str("reservation"),
+        }
+    }
+}
+
+/// Polarity for a trait predicate. May either be negative or positive.
+/// Distinguished from [`ImplPolarity`] since we never compute goals with
+/// "reservation" level.
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub enum PredicatePolarity {
+    /// `Type: Trait`
+    Positive,
+    /// `Type: !Trait`
+    Negative,
+}
+
+impl PredicatePolarity {
+    /// Flips polarity by turning `Positive` into `Negative` and `Negative` into `Positive`.
+    pub fn flip(&self) -> PredicatePolarity {
+        match self {
+            PredicatePolarity::Positive => PredicatePolarity::Negative,
+            PredicatePolarity::Negative => PredicatePolarity::Positive,
+        }
+    }
+}
+
+impl fmt::Display for PredicatePolarity {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            Self::Positive => f.write_str("positive"),
+            Self::Negative => f.write_str("negative"),
+        }
+    }
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Debug(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub enum ExistentialPredicate<I: Interner> {
+    /// E.g., `Iterator`.
+    Trait(ExistentialTraitRef<I>),
+    /// E.g., `Iterator::Item = T`.
+    Projection(ExistentialProjection<I>),
+    /// E.g., `Send`.
+    AutoTrait(I::DefId),
+}
+
+// FIXME: Implement this the right way after
+impl<I: Interner> DebugWithInfcx<I> for ExistentialPredicate<I> {
+    fn fmt<Infcx: rustc_type_ir::InferCtxtLike<Interner = I>>(
+        this: rustc_type_ir::WithInfcx<'_, Infcx, &Self>,
+        f: &mut fmt::Formatter<'_>,
+    ) -> fmt::Result {
+        fmt::Debug::fmt(&this.data, f)
+    }
+}
+
+impl<I: Interner> ty::Binder<I, ExistentialPredicate<I>> {
+    /// Given an existential predicate like `?Self: PartialEq<u32>` (e.g., derived from `dyn PartialEq<u32>`),
+    /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self`
+    /// has been replaced with `self_ty` (e.g., `self_ty: PartialEq<u32>`, in our example).
+    pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> I::Clause {
+        match self.skip_binder() {
+            ExistentialPredicate::Trait(tr) => {
+                self.rebind(tr).with_self_ty(tcx, self_ty).upcast(tcx)
+            }
+            ExistentialPredicate::Projection(p) => {
+                self.rebind(p.with_self_ty(tcx, self_ty)).upcast(tcx)
+            }
+            ExistentialPredicate::AutoTrait(did) => {
+                let generics = tcx.generics_of(did);
+                let trait_ref = if generics.count() == 1 {
+                    ty::TraitRef::new(tcx, did, [self_ty])
+                } else {
+                    // If this is an ill-formed auto trait, then synthesize
+                    // new error args for the missing generics.
+                    let err_args = GenericArgs::extend_with_error(tcx, did, &[self_ty.into()]);
+                    ty::TraitRef::new(tcx, did, err_args)
+                };
+                self.rebind(trait_ref).upcast(tcx)
+            }
+        }
+    }
+}
+
+/// An existential reference to a trait, where `Self` is erased.
+/// For example, the trait object `Trait<'a, 'b, X, Y>` is:
+/// ```ignore (illustrative)
+/// exists T. T: Trait<'a, 'b, X, Y>
+/// ```
+/// The generic parameters don't include the erased `Self`, only trait
+/// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above).
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct ExistentialTraitRef<I: Interner> {
+    pub def_id: I::DefId,
+    pub args: I::GenericArgs,
+}
+
+impl<I: Interner> ExistentialTraitRef<I> {
+    pub fn erase_self_ty(interner: I, trait_ref: TraitRef<I>) -> ExistentialTraitRef<I> {
+        // Assert there is a Self.
+        trait_ref.args.type_at(0);
+
+        ExistentialTraitRef {
+            def_id: trait_ref.def_id,
+            args: interner.mk_args(&trait_ref.args[1..]),
+        }
+    }
+
+    /// Object types don't have a self type specified. Therefore, when
+    /// we convert the principal trait-ref into a normal trait-ref,
+    /// you must give *some* self type. A common choice is `mk_err()`
+    /// or some placeholder type.
+    pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> TraitRef<I> {
+        // otherwise the escaping vars would be captured by the binder
+        // debug_assert!(!self_ty.has_escaping_bound_vars());
+
+        TraitRef::new(
+            interner,
+            self.def_id,
+            [self_ty.into()].into_iter().chain(self.args.into_iter()),
+        )
+    }
+}
+
+impl<I: Interner> ty::Binder<I, ExistentialTraitRef<I>> {
+    pub fn def_id(&self) -> I::DefId {
+        self.skip_binder().def_id
+    }
+
+    /// Object types don't have a self type specified. Therefore, when
+    /// we convert the principal trait-ref into a normal trait-ref,
+    /// you must give *some* self type. A common choice is `mk_err()`
+    /// or some placeholder type.
+    pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ty::Binder<I, TraitRef<I>> {
+        self.map_bound(|trait_ref| trait_ref.with_self_ty(tcx, self_ty))
+    }
+}
+
+/// A `ProjectionPredicate` for an `ExistentialTraitRef`.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct ExistentialProjection<I: Interner> {
+    pub def_id: I::DefId,
+    pub args: I::GenericArgs,
+    pub term: I::Term,
+}
+
+impl<I: Interner> ExistentialProjection<I> {
+    /// Extracts the underlying existential trait reference from this projection.
+    /// For example, if this is a projection of `exists T. <T as Iterator>::Item == X`,
+    /// then this function would return an `exists T. T: Iterator` existential trait
+    /// reference.
+    pub fn trait_ref(&self, interner: I) -> ExistentialTraitRef<I> {
+        let def_id = interner.parent(self.def_id);
+        let args_count = interner.generics_of(def_id).count() - 1;
+        let args = interner.mk_args(&self.args[..args_count]);
+        ExistentialTraitRef { def_id, args }
+    }
+
+    pub fn with_self_ty(&self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
+        // otherwise the escaping regions would be captured by the binders
+        debug_assert!(!self_ty.has_escaping_bound_vars());
+
+        ProjectionPredicate {
+            projection_term: AliasTerm::new(
+                interner,
+                self.def_id,
+                [self_ty.into()].into_iter().chain(self.args),
+            ),
+            term: self.term,
+        }
+    }
+
+    pub fn erase_self_ty(interner: I, projection_predicate: ProjectionPredicate<I>) -> Self {
+        // Assert there is a Self.
+        projection_predicate.projection_term.args.type_at(0);
+
+        Self {
+            def_id: projection_predicate.projection_term.def_id,
+            args: interner.mk_args(&projection_predicate.projection_term.args[1..]),
+            term: projection_predicate.term,
+        }
+    }
+}
+
+impl<I: Interner> ty::Binder<I, ExistentialProjection<I>> {
+    pub fn with_self_ty(&self, tcx: I, self_ty: I::Ty) -> ty::Binder<I, ProjectionPredicate<I>> {
+        self.map_bound(|p| p.with_self_ty(tcx, self_ty))
+    }
+
+    pub fn item_def_id(&self) -> I::DefId {
+        self.skip_binder().def_id
+    }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
+pub enum AliasTermKind {
+    /// A projection `<Type as Trait>::AssocType`.
+    /// Can get normalized away if monomorphic enough.
+    ProjectionTy,
+    /// An associated type in an inherent `impl`
+    InherentTy,
+    /// An opaque type (usually from `impl Trait` in type aliases or function return types)
+    /// Can only be normalized away in RevealAll mode
+    OpaqueTy,
+    /// A type alias that actually checks its trait bounds.
+    /// Currently only used if the type alias references opaque types.
+    /// Can always be normalized away.
+    WeakTy,
+    /// An unevaluated const coming from a generic const expression.
+    UnevaluatedConst,
+    /// An unevaluated const coming from an associated const.
+    ProjectionConst,
+}
+
+impl AliasTermKind {
+    pub fn descr(self) -> &'static str {
+        match self {
+            AliasTermKind::ProjectionTy => "associated type",
+            AliasTermKind::ProjectionConst => "associated const",
+            AliasTermKind::InherentTy => "inherent associated type",
+            AliasTermKind::OpaqueTy => "opaque type",
+            AliasTermKind::WeakTy => "type alias",
+            AliasTermKind::UnevaluatedConst => "unevaluated constant",
+        }
+    }
+}
+
+/// Represents the unprojected term of a projection goal.
+///
+/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
+/// * For an inherent projection, this would be `Ty::N<...>`.
+/// * For an opaque type, there is no explicit syntax.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct AliasTerm<I: Interner> {
+    /// The parameters of the associated or opaque item.
+    ///
+    /// For a projection, these are the generic parameters for the trait and the
+    /// GAT parameters, if there are any.
+    ///
+    /// For an inherent projection, they consist of the self type and the GAT parameters,
+    /// if there are any.
+    ///
+    /// For RPIT the generic parameters are for the generics of the function,
+    /// while for TAIT it is used for the generic parameters of the alias.
+    pub args: I::GenericArgs,
+
+    /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
+    /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
+    /// this is an opaque.
+    ///
+    /// During codegen, `interner.type_of(def_id)` can be used to get the type of the
+    /// underlying type if the type is an opaque.
+    ///
+    /// Note that if this is an associated type, this is not the `DefId` of the
+    /// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`,
+    /// aka. `interner.parent(def_id)`.
+    pub def_id: I::DefId,
+
+    /// This field exists to prevent the creation of `AliasTerm` without using
+    /// [AliasTerm::new].
+    _use_alias_term_new_instead: (),
+}
+
+impl<I: Interner> std::fmt::Debug for AliasTerm<I> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        WithInfcx::with_no_infcx(self).fmt(f)
+    }
+}
+impl<I: Interner> DebugWithInfcx<I> for AliasTerm<I> {
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
+        f: &mut std::fmt::Formatter<'_>,
+    ) -> std::fmt::Result {
+        f.debug_struct("AliasTerm")
+            .field("args", &this.map(|data| data.args))
+            .field("def_id", &this.data.def_id)
+            .finish()
+    }
+}
+
+impl<I: Interner> AliasTerm<I> {
+    pub fn new(
+        interner: I,
+        def_id: I::DefId,
+        args: impl IntoIterator<Item: Into<I::GenericArg>>,
+    ) -> AliasTerm<I> {
+        let args = interner.check_and_mk_args(def_id, args);
+        AliasTerm { def_id, args, _use_alias_term_new_instead: () }
+    }
+
+    pub fn expect_ty(self, interner: I) -> ty::AliasTy<I> {
+        match self.kind(interner) {
+            AliasTermKind::ProjectionTy
+            | AliasTermKind::InherentTy
+            | AliasTermKind::OpaqueTy
+            | AliasTermKind::WeakTy => {}
+            AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
+                panic!("Cannot turn `UnevaluatedConst` into `AliasTy`")
+            }
+        }
+        ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () }
+    }
+
+    pub fn kind(self, interner: I) -> AliasTermKind {
+        interner.alias_term_kind(self)
+    }
+
+    pub fn to_term(self, interner: I) -> I::Term {
+        match self.kind(interner) {
+            AliasTermKind::ProjectionTy => Ty::new_alias(
+                interner,
+                ty::AliasTyKind::Projection,
+                ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
+            )
+            .into(),
+            AliasTermKind::InherentTy => Ty::new_alias(
+                interner,
+                ty::AliasTyKind::Inherent,
+                ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
+            )
+            .into(),
+            AliasTermKind::OpaqueTy => Ty::new_alias(
+                interner,
+                ty::AliasTyKind::Opaque,
+                ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
+            )
+            .into(),
+            AliasTermKind::WeakTy => Ty::new_alias(
+                interner,
+                ty::AliasTyKind::Weak,
+                ty::AliasTy { def_id: self.def_id, args: self.args, _use_alias_ty_new_instead: () },
+            )
+            .into(),
+            AliasTermKind::UnevaluatedConst | AliasTermKind::ProjectionConst => {
+                I::Const::new_unevaluated(
+                    interner,
+                    ty::UnevaluatedConst::new(self.def_id, self.args),
+                    interner.type_of_instantiated(self.def_id, self.args),
+                )
+                .into()
+            }
+        }
+    }
+}
+
+/// The following methods work only with (trait) associated type projections.
+impl<I: Interner> AliasTerm<I> {
+    pub fn self_ty(self) -> I::Ty {
+        self.args.type_at(0)
+    }
+
+    pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
+        AliasTerm::new(
+            interner,
+            self.def_id,
+            [self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)),
+        )
+    }
+
+    pub fn trait_def_id(self, interner: I) -> I::DefId {
+        assert!(
+            matches!(
+                self.kind(interner),
+                AliasTermKind::ProjectionTy | AliasTermKind::ProjectionConst
+            ),
+            "expected a projection"
+        );
+        interner.parent(self.def_id)
+    }
+
+    /// Extracts the underlying trait reference and own args from this projection.
+    /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
+    /// then this function would return a `T: StreamingIterator` trait reference and
+    /// `['a]` as the own args.
+    pub fn trait_ref_and_own_args(self, interner: I) -> (TraitRef<I>, I::OwnItemArgs) {
+        interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
+    }
+
+    /// Extracts the underlying trait reference from this projection.
+    /// For example, if this is a projection of `<T as Iterator>::Item`,
+    /// then this function would return a `T: Iterator` trait reference.
+    ///
+    /// WARNING: This will drop the args for generic associated types
+    /// consider calling [Self::trait_ref_and_own_args] to get those
+    /// as well.
+    pub fn trait_ref(self, interner: I) -> TraitRef<I> {
+        self.trait_ref_and_own_args(interner).0
+    }
+}
+
+impl<I: Interner> From<ty::AliasTy<I>> for AliasTerm<I> {
+    fn from(ty: ty::AliasTy<I>) -> Self {
+        AliasTerm { args: ty.args, def_id: ty.def_id, _use_alias_term_new_instead: () }
+    }
+}
+
+impl<I: Interner> From<ty::UnevaluatedConst<I>> for AliasTerm<I> {
+    fn from(ct: ty::UnevaluatedConst<I>) -> Self {
+        AliasTerm { args: ct.args, def_id: ct.def, _use_alias_term_new_instead: () }
+    }
+}
+
+/// This kind of predicate has no *direct* correspondent in the
+/// syntax, but it roughly corresponds to the syntactic forms:
+///
+/// 1. `T: TraitRef<..., Item = Type>`
+/// 2. `<T as TraitRef<...>>::Item == Type` (NYI)
+///
+/// In particular, form #1 is "desugared" to the combination of a
+/// normal trait predicate (`T: TraitRef<...>`) and one of these
+/// predicates. Form #2 is a broader form in that it also permits
+/// equality between arbitrary types. Processing an instance of
+/// Form #2 eventually yields one of these `ProjectionPredicate`
+/// instances to normalize the LHS.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct ProjectionPredicate<I: Interner> {
+    pub projection_term: AliasTerm<I>,
+    pub term: I::Term,
+}
+
+impl<I: Interner> ProjectionPredicate<I> {
+    pub fn self_ty(self) -> I::Ty {
+        self.projection_term.self_ty()
+    }
+
+    pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> ProjectionPredicate<I> {
+        Self { projection_term: self.projection_term.with_self_ty(interner, self_ty), ..self }
+    }
+
+    pub fn trait_def_id(self, interner: I) -> I::DefId {
+        self.projection_term.trait_def_id(interner)
+    }
+
+    pub fn def_id(self) -> I::DefId {
+        self.projection_term.def_id
+    }
+}
+
+impl<I: Interner> ty::Binder<I, ProjectionPredicate<I>> {
+    /// Returns the `DefId` of the trait of the associated item being projected.
+    #[inline]
+    pub fn trait_def_id(&self, tcx: I) -> I::DefId {
+        self.skip_binder().projection_term.trait_def_id(tcx)
+    }
+
+    /// Get the trait ref required for this projection to be well formed.
+    /// Note that for generic associated types the predicates of the associated
+    /// type also need to be checked.
+    #[inline]
+    pub fn required_poly_trait_ref(&self, tcx: I) -> ty::Binder<I, TraitRef<I>> {
+        // Note: unlike with `TraitRef::to_poly_trait_ref()`,
+        // `self.0.trait_ref` is permitted to have escaping regions.
+        // This is because here `self` has a `Binder` and so does our
+        // return value, so we are preserving the number of binding
+        // levels.
+        self.map_bound(|predicate| predicate.projection_term.trait_ref(tcx))
+    }
+
+    pub fn term(&self) -> ty::Binder<I, I::Term> {
+        self.map_bound(|predicate| predicate.term)
+    }
+
+    /// The `DefId` of the `TraitItem` for the associated type.
+    ///
+    /// Note that this is not the `DefId` of the `TraitRef` containing this
+    /// associated type, which is in `tcx.associated_item(projection_def_id()).container`.
+    pub fn projection_def_id(&self) -> I::DefId {
+        // Ok to skip binder since trait `DefId` does not care about regions.
+        self.skip_binder().projection_term.def_id
+    }
+}
+
+impl<I: Interner> fmt::Debug for ProjectionPredicate<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "ProjectionPredicate({:?}, {:?})", self.projection_term, self.term)
+    }
+}
+
+/// Used by the new solver. Unlike a `ProjectionPredicate` this can only be
+/// proven by actually normalizing `alias`.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct NormalizesTo<I: Interner> {
+    pub alias: AliasTerm<I>,
+    pub term: I::Term,
+}
+
+impl<I: Interner> NormalizesTo<I> {
+    pub fn self_ty(self) -> I::Ty {
+        self.alias.self_ty()
+    }
+
+    pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> NormalizesTo<I> {
+        Self { alias: self.alias.with_self_ty(interner, self_ty), ..self }
+    }
+
+    pub fn trait_def_id(self, interner: I) -> I::DefId {
+        self.alias.trait_def_id(interner)
+    }
+
+    pub fn def_id(self) -> I::DefId {
+        self.alias.def_id
+    }
+}
+
+impl<I: Interner> fmt::Debug for NormalizesTo<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "NormalizesTo({:?}, {:?})", self.alias, self.term)
+    }
+}
+
+/// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates
+/// whether the `a` type is the type that we should label as "expected" when
+/// presenting user diagnostics.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Debug(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct SubtypePredicate<I: Interner> {
+    pub a_is_expected: bool,
+    pub a: I::Ty,
+    pub b: I::Ty,
+}
+
+/// Encodes that we have to coerce *from* the `a` type to the `b` type.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Debug(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct CoercePredicate<I: Interner> {
+    pub a: I::Ty,
+    pub b: I::Ty,
+}
diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs
index 5260d90..efe270e 100644
--- a/compiler/rustc_type_ir/src/predicate_kind.rs
+++ b/compiler/rustc_type_ir/src/predicate_kind.rs
@@ -1,33 +1,31 @@
-use rustc_ast_ir::try_visit;
-use rustc_ast_ir::visit::VisitorResult;
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
+use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
 use std::fmt;
 
-use crate::fold::{FallibleTypeFolder, TypeFoldable};
-use crate::visit::{TypeVisitable, TypeVisitor};
-use crate::Interner;
+use crate::{self as ty, Interner};
 
 /// A clause is something that can appear in where bounds or be inferred
 /// by implied bounds.
 #[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))]
+#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub enum ClauseKind<I: Interner> {
     /// Corresponds to `where Foo: Bar<A, B, C>`. `Foo` here would be
     /// the `Self` type of the trait reference and `A`, `B`, and `C`
     /// would be the type parameters.
-    Trait(I::TraitPredicate),
+    Trait(ty::TraitPredicate<I>),
 
-    /// `where 'a: 'b`
-    RegionOutlives(I::RegionOutlivesPredicate),
+    /// `where 'a: 'r`
+    RegionOutlives(ty::OutlivesPredicate<I, I::Region>),
 
-    /// `where T: 'a`
-    TypeOutlives(I::TypeOutlivesPredicate),
+    /// `where T: 'r`
+    TypeOutlives(ty::OutlivesPredicate<I, I::Ty>),
 
     /// `where <T as TraitRef>::Name == X`, approximately.
     /// See the `ProjectionPredicate` struct for details.
-    Projection(I::ProjectionPredicate),
+    Projection(ty::ProjectionPredicate<I>),
 
     /// Ensures that a const generic argument to a parameter `const N: u8`
     /// is of type `u8`.
@@ -55,61 +53,6 @@
     }
 }
 
-impl<I: Interner> Eq for ClauseKind<I> {}
-
-impl<I: Interner> TypeFoldable<I> for ClauseKind<I>
-where
-    I::Ty: TypeFoldable<I>,
-    I::Const: TypeFoldable<I>,
-    I::GenericArg: TypeFoldable<I>,
-    I::TraitPredicate: TypeFoldable<I>,
-    I::ProjectionPredicate: TypeFoldable<I>,
-    I::TypeOutlivesPredicate: TypeFoldable<I>,
-    I::RegionOutlivesPredicate: TypeFoldable<I>,
-{
-    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        Ok(match self {
-            ClauseKind::Trait(p) => ClauseKind::Trait(p.try_fold_with(folder)?),
-            ClauseKind::RegionOutlives(p) => ClauseKind::RegionOutlives(p.try_fold_with(folder)?),
-            ClauseKind::TypeOutlives(p) => ClauseKind::TypeOutlives(p.try_fold_with(folder)?),
-            ClauseKind::Projection(p) => ClauseKind::Projection(p.try_fold_with(folder)?),
-            ClauseKind::ConstArgHasType(c, t) => {
-                ClauseKind::ConstArgHasType(c.try_fold_with(folder)?, t.try_fold_with(folder)?)
-            }
-            ClauseKind::WellFormed(p) => ClauseKind::WellFormed(p.try_fold_with(folder)?),
-            ClauseKind::ConstEvaluatable(p) => {
-                ClauseKind::ConstEvaluatable(p.try_fold_with(folder)?)
-            }
-        })
-    }
-}
-
-impl<I: Interner> TypeVisitable<I> for ClauseKind<I>
-where
-    I::Ty: TypeVisitable<I>,
-    I::Const: TypeVisitable<I>,
-    I::GenericArg: TypeVisitable<I>,
-    I::TraitPredicate: TypeVisitable<I>,
-    I::ProjectionPredicate: TypeVisitable<I>,
-    I::TypeOutlivesPredicate: TypeVisitable<I>,
-    I::RegionOutlivesPredicate: TypeVisitable<I>,
-{
-    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
-        match self {
-            ClauseKind::Trait(p) => p.visit_with(visitor),
-            ClauseKind::RegionOutlives(p) => p.visit_with(visitor),
-            ClauseKind::TypeOutlives(p) => p.visit_with(visitor),
-            ClauseKind::Projection(p) => p.visit_with(visitor),
-            ClauseKind::ConstArgHasType(c, t) => {
-                try_visit!(c.visit_with(visitor));
-                t.visit_with(visitor)
-            }
-            ClauseKind::WellFormed(p) => p.visit_with(visitor),
-            ClauseKind::ConstEvaluatable(p) => p.visit_with(visitor),
-        }
-    }
-}
-
 #[derive(derivative::Derivative)]
 #[derivative(
     Clone(bound = ""),
@@ -118,6 +61,7 @@
     PartialEq(bound = ""),
     Eq(bound = "")
 )]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub enum PredicateKind<I: Interner> {
     /// Prove a clause
@@ -131,7 +75,7 @@
     /// This obligation is created most often when we have two
     /// unresolved type variables and hence don't have enough
     /// information to process the subtyping obligation yet.
-    Subtype(I::SubtypePredicate),
+    Subtype(ty::SubtypePredicate<I>),
 
     /// `T1` coerced to `T2`
     ///
@@ -141,7 +85,7 @@
     /// obligation yet. At the moment, we actually process coercions
     /// very much like subtyping and don't handle the full coercion
     /// logic.
-    Coerce(I::CoercePredicate),
+    Coerce(ty::CoercePredicate<I>),
 
     /// Constants must be equal. The first component is the const that is expected.
     ConstEquate(I::Const, I::Const),
@@ -158,7 +102,7 @@
     /// `T as Trait>::Assoc`, `Projection(<T as Trait>::Assoc, ?x)` constrains `?x`
     /// to `<T as Trait>::Assoc` while `NormalizesTo(<T as Trait>::Assoc, ?x)`
     /// results in `NoSolution`.
-    NormalizesTo(I::NormalizesTo),
+    NormalizesTo(ty::NormalizesTo<I>),
 
     /// Separate from `ClauseKind::Projection` which is used for normalization in new solver.
     /// This predicate requires two terms to be equal to eachother.
@@ -167,69 +111,6 @@
     AliasRelate(I::Term, I::Term, AliasRelationDirection),
 }
 
-impl<I: Interner> TypeFoldable<I> for PredicateKind<I>
-where
-    I::DefId: TypeFoldable<I>,
-    I::Const: TypeFoldable<I>,
-    I::GenericArgs: TypeFoldable<I>,
-    I::Term: TypeFoldable<I>,
-    I::CoercePredicate: TypeFoldable<I>,
-    I::SubtypePredicate: TypeFoldable<I>,
-    I::NormalizesTo: TypeFoldable<I>,
-    ClauseKind<I>: TypeFoldable<I>,
-{
-    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        Ok(match self {
-            PredicateKind::Clause(c) => PredicateKind::Clause(c.try_fold_with(folder)?),
-            PredicateKind::ObjectSafe(d) => PredicateKind::ObjectSafe(d.try_fold_with(folder)?),
-            PredicateKind::Subtype(s) => PredicateKind::Subtype(s.try_fold_with(folder)?),
-            PredicateKind::Coerce(s) => PredicateKind::Coerce(s.try_fold_with(folder)?),
-            PredicateKind::ConstEquate(a, b) => {
-                PredicateKind::ConstEquate(a.try_fold_with(folder)?, b.try_fold_with(folder)?)
-            }
-            PredicateKind::Ambiguous => PredicateKind::Ambiguous,
-            PredicateKind::NormalizesTo(p) => PredicateKind::NormalizesTo(p.try_fold_with(folder)?),
-            PredicateKind::AliasRelate(a, b, d) => PredicateKind::AliasRelate(
-                a.try_fold_with(folder)?,
-                b.try_fold_with(folder)?,
-                d.try_fold_with(folder)?,
-            ),
-        })
-    }
-}
-
-impl<I: Interner> TypeVisitable<I> for PredicateKind<I>
-where
-    I::DefId: TypeVisitable<I>,
-    I::Const: TypeVisitable<I>,
-    I::GenericArgs: TypeVisitable<I>,
-    I::Term: TypeVisitable<I>,
-    I::CoercePredicate: TypeVisitable<I>,
-    I::SubtypePredicate: TypeVisitable<I>,
-    I::NormalizesTo: TypeVisitable<I>,
-    ClauseKind<I>: TypeVisitable<I>,
-{
-    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
-        match self {
-            PredicateKind::Clause(p) => p.visit_with(visitor),
-            PredicateKind::ObjectSafe(d) => d.visit_with(visitor),
-            PredicateKind::Subtype(s) => s.visit_with(visitor),
-            PredicateKind::Coerce(s) => s.visit_with(visitor),
-            PredicateKind::ConstEquate(a, b) => {
-                try_visit!(a.visit_with(visitor));
-                b.visit_with(visitor)
-            }
-            PredicateKind::Ambiguous => V::Result::output(),
-            PredicateKind::NormalizesTo(p) => p.visit_with(visitor),
-            PredicateKind::AliasRelate(a, b, d) => {
-                try_visit!(a.visit_with(visitor));
-                try_visit!(b.visit_with(visitor));
-                d.visit_with(visitor)
-            }
-        }
-    }
-}
-
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)]
 #[cfg_attr(feature = "nightly", derive(HashStable_NoContext, Encodable, Decodable))]
 pub enum AliasRelationDirection {
diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs
index d1b86b4..48ade27 100644
--- a/compiler/rustc_type_ir/src/region_kind.rs
+++ b/compiler/rustc_type_ir/src/region_kind.rs
@@ -1,13 +1,35 @@
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 #[cfg(feature = "nightly")]
-use rustc_macros::{TyDecodable, TyEncodable};
+use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
 use std::fmt;
 
 use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
 
 use self::RegionKind::*;
 
+rustc_index::newtype_index! {
+    /// A **region** **v**ariable **ID**.
+    #[encodable]
+    #[orderable]
+    #[debug_format = "'?{}"]
+    #[gate_rustc_only]
+    #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+    pub struct RegionVid {}
+}
+
+impl<I: Interner> DebugWithInfcx<I> for RegionVid {
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
+        f: &mut core::fmt::Formatter<'_>,
+    ) -> core::fmt::Result {
+        match this.infcx.universe_of_lt(*this.data) {
+            Some(universe) => write!(f, "'?{}_{}", this.data.index(), universe.index()),
+            None => write!(f, "{:?}", this.data),
+        }
+    }
+}
+
 /// Representation of regions. Note that the NLL checker uses a distinct
 /// representation of regions. For this reason, it internally replaces all the
 /// regions with inference variables -- the index of the variable is then used
@@ -115,7 +137,7 @@
 /// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
 /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html
 #[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))]
+#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable))]
 pub enum RegionKind<I: Interner> {
     /// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`.
@@ -152,7 +174,7 @@
     ReStatic,
 
     /// A region variable. Should not exist outside of type inference.
-    ReVar(I::InferRegion),
+    ReVar(RegionVid),
 
     /// A placeholder region -- the higher-ranked version of `ReLateParam`.
     /// Should not exist outside of type inference.
@@ -208,9 +230,6 @@
     }
 }
 
-// This is manually implemented because a derive would require `I: Eq`
-impl<I: Interner> Eq for RegionKind<I> {}
-
 impl<I: Interner> DebugWithInfcx<I> for RegionKind<I> {
     fn fmt<Infcx: InferCtxtLike<Interner = I>>(
         this: WithInfcx<'_, Infcx, &Self>,
@@ -254,7 +273,6 @@
     I::EarlyParamRegion: HashStable<CTX>,
     I::BoundRegion: HashStable<CTX>,
     I::LateParamRegion: HashStable<CTX>,
-    I::InferRegion: HashStable<CTX>,
     I::PlaceholderRegion: HashStable<CTX>,
 {
     #[inline]
diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs
new file mode 100644
index 0000000..3c24e85
--- /dev/null
+++ b/compiler/rustc_type_ir/src/solve.rs
@@ -0,0 +1,278 @@
+pub mod inspect;
+
+use std::fmt;
+use std::hash::Hash;
+
+#[cfg(feature = "nightly")]
+use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable};
+use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
+
+use crate::{Canonical, CanonicalVarValues, Interner, Upcast};
+
+pub type CanonicalInput<I, T = <I as Interner>::Predicate> = Canonical<I, QueryInput<I, T>>;
+pub type CanonicalResponse<I> = Canonical<I, Response<I>>;
+/// The result of evaluating a canonical query.
+///
+/// FIXME: We use a different type than the existing canonical queries. This is because
+/// we need to add a `Certainty` for `overflow` and may want to restructure this code without
+/// having to worry about changes to currently used code. Once we've made progress on this
+/// solver, merge the two responses again.
+pub type QueryResult<I> = Result<CanonicalResponse<I>, NoSolution>;
+
+#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
+#[derive(TypeFoldable_Generic, TypeVisitable_Generic)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub struct NoSolution;
+
+/// A goal is a statement, i.e. `predicate`, we want to prove
+/// given some assumptions, i.e. `param_env`.
+///
+/// Most of the time the `param_env` contains the `where`-bounds of the function
+/// we're currently typechecking while the `predicate` is some trait bound.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = "P: Clone"),
+    Copy(bound = "P: Copy"),
+    Hash(bound = "P: Hash"),
+    PartialEq(bound = "P: PartialEq"),
+    Eq(bound = "P: Eq"),
+    Debug(bound = "P: fmt::Debug")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct Goal<I: Interner, P> {
+    pub param_env: I::ParamEnv,
+    pub predicate: P,
+}
+
+impl<I: Interner, P> Goal<I, P> {
+    pub fn new(tcx: I, param_env: I::ParamEnv, predicate: impl Upcast<I, P>) -> Goal<I, P> {
+        Goal { param_env, predicate: predicate.upcast(tcx) }
+    }
+
+    /// Updates the goal to one with a different `predicate` but the same `param_env`.
+    pub fn with<Q>(self, tcx: I, predicate: impl Upcast<I, Q>) -> Goal<I, Q> {
+        Goal { param_env: self.param_env, predicate: predicate.upcast(tcx) }
+    }
+}
+
+/// Why a specific goal has to be proven.
+///
+/// This is necessary as we treat nested goals different depending on
+/// their source.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub enum GoalSource {
+    Misc,
+    /// We're proving a where-bound of an impl.
+    ///
+    /// FIXME(-Znext-solver=coinductive): Explain how and why this
+    /// changes whether cycles are coinductive.
+    ///
+    /// This also impacts whether we erase constraints on overflow.
+    /// Erasing constraints is generally very useful for perf and also
+    /// results in better error messages by avoiding spurious errors.
+    /// We do not erase overflow constraints in `normalizes-to` goals unless
+    /// they are from an impl where-clause. This is necessary due to
+    /// backwards compatability, cc trait-system-refactor-initiatitive#70.
+    ImplWhereBound,
+    /// Instantiating a higher-ranked goal and re-proving it.
+    InstantiateHigherRanked,
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = "Goal<I, P>: Clone"),
+    Copy(bound = "Goal<I, P>: Copy"),
+    Hash(bound = "Goal<I, P>: Hash"),
+    PartialEq(bound = "Goal<I, P>: PartialEq"),
+    Eq(bound = "Goal<I, P>: Eq"),
+    Debug(bound = "Goal<I, P>: fmt::Debug")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct QueryInput<I: Interner, P> {
+    pub goal: Goal<I, P>,
+    pub predefined_opaques_in_body: I::PredefinedOpaques,
+}
+
+/// Possible ways the given goal can be proven.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Debug(bound = "")
+)]
+pub enum CandidateSource<I: Interner> {
+    /// A user written impl.
+    ///
+    /// ## Examples
+    ///
+    /// ```rust
+    /// fn main() {
+    ///     let x: Vec<u32> = Vec::new();
+    ///     // This uses the impl from the standard library to prove `Vec<T>: Clone`.
+    ///     let y = x.clone();
+    /// }
+    /// ```
+    Impl(I::DefId),
+    /// A builtin impl generated by the compiler. When adding a new special
+    /// trait, try to use actual impls whenever possible. Builtin impls should
+    /// only be used in cases where the impl cannot be manually be written.
+    ///
+    /// Notable examples are auto traits, `Sized`, and `DiscriminantKind`.
+    /// For a list of all traits with builtin impls, check out the
+    /// `EvalCtxt::assemble_builtin_impl_candidates` method.
+    BuiltinImpl(BuiltinImplSource),
+    /// An assumption from the environment.
+    ///
+    /// More precisely we've used the `n-th` assumption in the `param_env`.
+    ///
+    /// ## Examples
+    ///
+    /// ```rust
+    /// fn is_clone<T: Clone>(x: T) -> (T, T) {
+    ///     // This uses the assumption `T: Clone` from the `where`-bounds
+    ///     // to prove `T: Clone`.
+    ///     (x.clone(), x)
+    /// }
+    /// ```
+    ParamEnv(usize),
+    /// If the self type is an alias type, e.g. an opaque type or a projection,
+    /// we know the bounds on that alias to hold even without knowing its concrete
+    /// underlying type.
+    ///
+    /// More precisely this candidate is using the `n-th` bound in the `item_bounds` of
+    /// the self type.
+    ///
+    /// ## Examples
+    ///
+    /// ```rust
+    /// trait Trait {
+    ///     type Assoc: Clone;
+    /// }
+    ///
+    /// fn foo<T: Trait>(x: <T as Trait>::Assoc) {
+    ///     // We prove `<T as Trait>::Assoc` by looking at the bounds on `Assoc` in
+    ///     // in the trait definition.
+    ///     let _y = x.clone();
+    /// }
+    /// ```
+    AliasBound,
+    /// A candidate that is registered only during coherence to represent some
+    /// yet-unknown impl that could be produced downstream without violating orphan
+    /// rules.
+    // FIXME: Merge this with the forced ambiguity candidates, so those don't use `Misc`.
+    CoherenceUnknowable,
+}
+
+#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext, TyEncodable, TyDecodable))]
+pub enum BuiltinImplSource {
+    /// Some builtin impl we don't need to differentiate. This should be used
+    /// unless more specific information is necessary.
+    Misc,
+    /// A builtin impl for trait objects.
+    ///
+    /// The vtable is formed by concatenating together the method lists of
+    /// the base object trait and all supertraits, pointers to supertrait vtable will
+    /// be provided when necessary; this is the start of `upcast_trait_ref`'s methods
+    /// in that vtable.
+    Object { vtable_base: usize },
+    /// The vtable is formed by concatenating together the method lists of
+    /// the base object trait and all supertraits, pointers to supertrait vtable will
+    /// be provided when necessary; this is the position of `upcast_trait_ref`'s vtable
+    /// within that vtable.
+    TraitUpcasting { vtable_vptr_slot: Option<usize> },
+    /// Unsizing a tuple like `(A, B, ..., X)` to `(A, B, ..., Y)` if `X` unsizes to `Y`.
+    ///
+    /// This needs to be a separate variant as it is still unstable and we need to emit
+    /// a feature error when using it on stable.
+    TupleUnsizing,
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Debug(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub struct Response<I: Interner> {
+    pub certainty: Certainty,
+    pub var_values: CanonicalVarValues<I>,
+    /// Additional constraints returned by this query.
+    pub external_constraints: I::ExternalConstraints,
+}
+
+#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub enum Certainty {
+    Yes,
+    Maybe(MaybeCause),
+}
+
+impl Certainty {
+    pub const AMBIGUOUS: Certainty = Certainty::Maybe(MaybeCause::Ambiguity);
+
+    /// Use this function to merge the certainty of multiple nested subgoals.
+    ///
+    /// Given an impl like `impl<T: Foo + Bar> Baz for T {}`, we have 2 nested
+    /// subgoals whenever we use the impl as a candidate: `T: Foo` and `T: Bar`.
+    /// If evaluating `T: Foo` results in ambiguity and `T: Bar` results in
+    /// success, we merge these two responses. This results in ambiguity.
+    ///
+    /// If we unify ambiguity with overflow, we return overflow. This doesn't matter
+    /// inside of the solver as we do not distinguish ambiguity from overflow. It does
+    /// however matter for diagnostics. If `T: Foo` resulted in overflow and `T: Bar`
+    /// in ambiguity without changing the inference state, we still want to tell the
+    /// user that `T: Baz` results in overflow.
+    pub fn unify_with(self, other: Certainty) -> Certainty {
+        match (self, other) {
+            (Certainty::Yes, Certainty::Yes) => Certainty::Yes,
+            (Certainty::Yes, Certainty::Maybe(_)) => other,
+            (Certainty::Maybe(_), Certainty::Yes) => self,
+            (Certainty::Maybe(a), Certainty::Maybe(b)) => Certainty::Maybe(a.unify_with(b)),
+        }
+    }
+
+    pub const fn overflow(suggest_increasing_limit: bool) -> Certainty {
+        Certainty::Maybe(MaybeCause::Overflow { suggest_increasing_limit })
+    }
+}
+
+/// Why we failed to evaluate a goal.
+#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))]
+pub enum MaybeCause {
+    /// We failed due to ambiguity. This ambiguity can either
+    /// be a true ambiguity, i.e. there are multiple different answers,
+    /// or we hit a case where we just don't bother, e.g. `?x: Trait` goals.
+    Ambiguity,
+    /// We gave up due to an overflow, most often by hitting the recursion limit.
+    Overflow { suggest_increasing_limit: bool },
+}
+
+impl MaybeCause {
+    fn unify_with(self, other: MaybeCause) -> MaybeCause {
+        match (self, other) {
+            (MaybeCause::Ambiguity, MaybeCause::Ambiguity) => MaybeCause::Ambiguity,
+            (MaybeCause::Ambiguity, MaybeCause::Overflow { .. }) => other,
+            (MaybeCause::Overflow { .. }, MaybeCause::Ambiguity) => self,
+            (
+                MaybeCause::Overflow { suggest_increasing_limit: a },
+                MaybeCause::Overflow { suggest_increasing_limit: b },
+            ) => MaybeCause::Overflow { suggest_increasing_limit: a || b },
+        }
+    }
+}
diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs
new file mode 100644
index 0000000..c4f6ee2
--- /dev/null
+++ b/compiler/rustc_type_ir/src/solve/inspect.rs
@@ -0,0 +1,189 @@
+//! Data structure used to inspect trait solver behavior.
+//!
+//! During trait solving we optionally build "proof trees", the root of
+//! which is a [GoalEvaluation] with [GoalEvaluationKind::Root]. These
+//! trees are used to improve the debug experience and are also used by
+//! the compiler itself to provide necessary context for error messages.
+//!
+//! Because each nested goal in the solver gets [canonicalized] separately
+//! and we discard inference progress via "probes", we cannot mechanically
+//! use proof trees without somehow "lifting up" data local to the current
+//! `InferCtxt`. Any data used mechanically is therefore canonicalized and
+//! stored as [CanonicalState]. As printing canonicalized data worsens the
+//! debugging dumps, we do not simply canonicalize everything.
+//!
+//! This means proof trees contain inference variables and placeholders
+//! local to a different `InferCtxt` which must not be used with the
+//! current one.
+//!
+//! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
+
+mod format;
+
+use std::fmt::{Debug, Write};
+use std::hash::Hash;
+
+use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic};
+
+use self::format::ProofTreeFormatter;
+use crate::solve::{
+    CandidateSource, CanonicalInput, Certainty, Goal, GoalSource, NoSolution, QueryInput,
+    QueryResult,
+};
+use crate::{Canonical, CanonicalVarValues, Interner};
+
+/// Some `data` together with information about how they relate to the input
+/// of the canonical query.
+///
+/// This is only ever used as [CanonicalState]. Any type information in proof
+/// trees used mechanically has to be canonicalized as we otherwise leak
+/// inference variables from a nested `InferCtxt`.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = "T: Clone"),
+    Copy(bound = "T: Copy"),
+    PartialEq(bound = "T: PartialEq"),
+    Eq(bound = "T: Eq"),
+    Hash(bound = "T: Hash"),
+    Debug(bound = "T: Debug")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+pub struct State<I: Interner, T> {
+    pub var_values: CanonicalVarValues<I>,
+    pub data: T,
+}
+
+pub type CanonicalState<I, T> = Canonical<I, State<I, T>>;
+
+/// When evaluating the root goals we also store the
+/// original values for the `CanonicalVarValues` of the
+/// canonicalized goal. We use this to map any [CanonicalState]
+/// from the local `InferCtxt` of the solver query to
+/// the `InferCtxt` of the caller.
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+pub enum GoalEvaluationKind<I: Interner> {
+    Root { orig_values: Vec<I::GenericArg> },
+    Nested,
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""))]
+pub struct GoalEvaluation<I: Interner> {
+    pub uncanonicalized_goal: Goal<I, I::Predicate>,
+    pub kind: GoalEvaluationKind<I>,
+    pub evaluation: CanonicalGoalEvaluation<I>,
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+pub struct CanonicalGoalEvaluation<I: Interner> {
+    pub goal: CanonicalInput<I>,
+    pub kind: CanonicalGoalEvaluationKind<I>,
+    pub result: QueryResult<I>,
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+pub enum CanonicalGoalEvaluationKind<I: Interner> {
+    Overflow,
+    CycleInStack,
+    ProvisionalCacheHit,
+    Evaluation { revisions: I::GoalEvaluationSteps },
+}
+impl<I: Interner> Debug for GoalEvaluation<I> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        ProofTreeFormatter::new(f).format_goal_evaluation(self)
+    }
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+pub struct AddedGoalsEvaluation<I: Interner> {
+    pub evaluations: Vec<Vec<GoalEvaluation<I>>>,
+    pub result: Result<Certainty, NoSolution>,
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+pub struct GoalEvaluationStep<I: Interner> {
+    pub instantiated_goal: QueryInput<I, I::Predicate>,
+
+    /// The actual evaluation of the goal, always `ProbeKind::Root`.
+    pub evaluation: Probe<I>,
+}
+
+/// A self-contained computation during trait solving. This either
+/// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation
+/// of a goal.
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""))]
+pub struct Probe<I: Interner> {
+    /// What happened inside of this probe in chronological order.
+    pub steps: Vec<ProbeStep<I>>,
+    pub kind: ProbeKind<I>,
+    pub final_state: CanonicalState<I, ()>,
+}
+
+impl<I: Interner> Debug for Probe<I> {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        ProofTreeFormatter::new(f).format_probe(self)
+    }
+}
+
+#[derive(derivative::Derivative)]
+#[derivative(PartialEq(bound = ""), Eq(bound = ""), Hash(bound = ""), Debug(bound = ""))]
+pub enum ProbeStep<I: Interner> {
+    /// We added a goal to the `EvalCtxt` which will get proven
+    /// the next time `EvalCtxt::try_evaluate_added_goals` is called.
+    AddGoal(GoalSource, CanonicalState<I, Goal<I, I::Predicate>>),
+    /// The inside of a `EvalCtxt::try_evaluate_added_goals` call.
+    EvaluateGoals(AddedGoalsEvaluation<I>),
+    /// A call to `probe` while proving the current goal. This is
+    /// used whenever there are multiple candidates to prove the
+    /// current goalby .
+    NestedProbe(Probe<I>),
+    /// A trait goal was satisfied by an impl candidate.
+    RecordImplArgs { impl_args: CanonicalState<I, I::GenericArgs> },
+    /// A call to `EvalCtxt::evaluate_added_goals_make_canonical_response` with
+    /// `Certainty` was made. This is the certainty passed in, so it's not unified
+    /// with the certainty of the `try_evaluate_added_goals` that is done within;
+    /// if it's `Certainty::Yes`, then we can trust that the candidate is "finished"
+    /// and we didn't force ambiguity for some reason.
+    MakeCanonicalResponse { shallow_certainty: Certainty },
+}
+
+/// What kind of probe we're in. In case the probe represents a candidate, or
+/// the final result of the current goal - via [ProbeKind::Root] - we also
+/// store the [QueryResult].
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Hash(bound = ""),
+    Debug(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
+pub enum ProbeKind<I: Interner> {
+    /// The root inference context while proving a goal.
+    Root { result: QueryResult<I> },
+    /// Trying to normalize an alias by at least one step in `NormalizesTo`.
+    TryNormalizeNonRigid { result: QueryResult<I> },
+    /// Probe entered when normalizing the self ty during candidate assembly
+    NormalizedSelfTyAssembly,
+    /// A candidate for proving a trait or alias-relate goal.
+    TraitCandidate { source: CandidateSource<I>, result: QueryResult<I> },
+    /// Used in the probe that wraps normalizing the non-self type for the unsize
+    /// trait, which is also structurally matched on.
+    UnsizeAssembly,
+    /// During upcasting from some source object to target object type, used to
+    /// do a probe to find out what projection type(s) may be used to prove that
+    /// the source type upholds all of the target type's object bounds.
+    UpcastProjectionCompatibility,
+    /// Looking for param-env candidates that satisfy the trait ref for a projection.
+    ShadowedEnvProbing,
+    /// Try to unify an opaque type with an existing key in the storage.
+    OpaqueTypeStorageLookup { result: QueryResult<I> },
+}
diff --git a/compiler/rustc_middle/src/traits/solve/inspect/format.rs b/compiler/rustc_type_ir/src/solve/inspect/format.rs
similarity index 88%
rename from compiler/rustc_middle/src/traits/solve/inspect/format.rs
rename to compiler/rustc_type_ir/src/solve/inspect/format.rs
index e652f05..44ade04 100644
--- a/compiler/rustc_middle/src/traits/solve/inspect/format.rs
+++ b/compiler/rustc_type_ir/src/solve/inspect/format.rs
@@ -1,7 +1,10 @@
+use std::marker::PhantomData;
+
 use super::*;
 
-pub(super) struct ProofTreeFormatter<'a, 'b> {
+pub(super) struct ProofTreeFormatter<'a, 'b, I> {
     f: &'a mut (dyn Write + 'b),
+    _interner: PhantomData<I>,
 }
 
 enum IndentorState {
@@ -36,23 +39,24 @@
     }
 }
 
-impl<'a, 'b> ProofTreeFormatter<'a, 'b> {
+impl<'a, 'b, I: Interner> ProofTreeFormatter<'a, 'b, I> {
     pub(super) fn new(f: &'a mut (dyn Write + 'b)) -> Self {
-        ProofTreeFormatter { f }
+        ProofTreeFormatter { f, _interner: PhantomData }
     }
 
     fn nested<F>(&mut self, func: F) -> std::fmt::Result
     where
-        F: FnOnce(&mut ProofTreeFormatter<'_, '_>) -> std::fmt::Result,
+        F: FnOnce(&mut ProofTreeFormatter<'_, '_, I>) -> std::fmt::Result,
     {
         write!(self.f, " {{")?;
         func(&mut ProofTreeFormatter {
             f: &mut Indentor { f: self.f, state: IndentorState::StartWithNewline },
+            _interner: PhantomData,
         })?;
         writeln!(self.f, "}}")
     }
 
-    pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<'_>) -> std::fmt::Result {
+    pub(super) fn format_goal_evaluation(&mut self, eval: &GoalEvaluation<I>) -> std::fmt::Result {
         let goal_text = match eval.kind {
             GoalEvaluationKind::Root { orig_values: _ } => "ROOT GOAL",
             GoalEvaluationKind::Nested => "GOAL",
@@ -63,7 +67,7 @@
 
     pub(super) fn format_canonical_goal_evaluation(
         &mut self,
-        eval: &CanonicalGoalEvaluation<'_>,
+        eval: &CanonicalGoalEvaluation<I>,
     ) -> std::fmt::Result {
         writeln!(self.f, "GOAL: {:?}", eval.goal)?;
 
@@ -89,13 +93,13 @@
 
     pub(super) fn format_evaluation_step(
         &mut self,
-        evaluation_step: &GoalEvaluationStep<'_>,
+        evaluation_step: &GoalEvaluationStep<I>,
     ) -> std::fmt::Result {
         writeln!(self.f, "INSTANTIATED: {:?}", evaluation_step.instantiated_goal)?;
         self.format_probe(&evaluation_step.evaluation)
     }
 
-    pub(super) fn format_probe(&mut self, probe: &Probe<'_>) -> std::fmt::Result {
+    pub(super) fn format_probe(&mut self, probe: &Probe<I>) -> std::fmt::Result {
         match &probe.kind {
             ProbeKind::Root { result } => {
                 write!(self.f, "ROOT RESULT: {result:?}")
@@ -118,6 +122,9 @@
             ProbeKind::TraitCandidate { source, result } => {
                 write!(self.f, "CANDIDATE {source:?}: {result:?}")
             }
+            ProbeKind::ShadowedEnvProbing => {
+                write!(self.f, "PROBING FOR IMPLS SHADOWED BY PARAM-ENV CANDIDATE:")
+            }
         }?;
 
         self.nested(|this| {
@@ -147,7 +154,7 @@
 
     pub(super) fn format_added_goals_evaluation(
         &mut self,
-        added_goals_evaluation: &AddedGoalsEvaluation<'_>,
+        added_goals_evaluation: &AddedGoalsEvaluation<I>,
     ) -> std::fmt::Result {
         writeln!(self.f, "TRY_EVALUATE_ADDED_GOALS: {:?}", added_goals_evaluation.result)?;
 
diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs
index f2e4afe..38082bf 100644
--- a/compiler/rustc_type_ir/src/ty_kind.rs
+++ b/compiler/rustc_type_ir/src/ty_kind.rs
@@ -1,16 +1,14 @@
-use rustc_ast_ir::try_visit;
 #[cfg(feature = "nightly")]
 use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
 #[cfg(feature = "nightly")]
 use rustc_data_structures::unify::{EqUnifyValue, UnifyKey};
 #[cfg(feature = "nightly")]
 use rustc_macros::{Decodable, Encodable, HashStable_NoContext, TyDecodable, TyEncodable};
+use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic};
 use std::fmt;
 
-use crate::fold::{FallibleTypeFolder, TypeFoldable};
-use crate::visit::{TypeVisitable, TypeVisitor};
-use crate::Interner;
-use crate::{DebruijnIndex, DebugWithInfcx, InferCtxtLike, WithInfcx};
+use crate::inherent::*;
+use crate::{self as ty, DebruijnIndex, DebugWithInfcx, InferCtxtLike, Interner, WithInfcx};
 
 use self::TyKind::*;
 
@@ -33,7 +31,7 @@
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
 #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
-pub enum AliasKind {
+pub enum AliasTyKind {
     /// A projection `<Type as Trait>::AssocType`.
     /// Can get normalized away if monomorphic enough.
     Projection,
@@ -48,13 +46,13 @@
     Weak,
 }
 
-impl AliasKind {
+impl AliasTyKind {
     pub fn descr(self) -> &'static str {
         match self {
-            AliasKind::Projection => "associated type",
-            AliasKind::Inherent => "inherent associated type",
-            AliasKind::Opaque => "opaque type",
-            AliasKind::Weak => "type alias",
+            AliasTyKind::Projection => "associated type",
+            AliasTyKind::Inherent => "inherent associated type",
+            AliasTyKind::Opaque => "opaque type",
+            AliasTyKind::Weak => "type alias",
         }
     }
 }
@@ -65,7 +63,7 @@
 /// converted to this representation using `<dyn HirTyLowerer>::lower_ty`.
 #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")]
 #[derive(derivative::Derivative)]
-#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""))]
+#[derivative(Clone(bound = ""), Copy(bound = ""), Hash(bound = ""), Eq(bound = ""))]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
 pub enum TyKind<I: Interner> {
     /// The primitive boolean type. Written as `bool`.
@@ -90,7 +88,7 @@
     /// for `struct List<T>` and the args `[i32]`.
     ///
     /// Note that generic parameters in fields only get lazily instantiated
-    /// by using something like `adt_def.all_fields().map(|field| field.ty(tcx, args))`.
+    /// by using something like `adt_def.all_fields().map(|field| field.ty(interner, args))`.
     Adt(I::AdtDef, I::GenericArgs),
 
     /// An unsized FFI type that is opaque to Rust. Written as `extern type T`.
@@ -203,7 +201,7 @@
     /// A projection, opaque type, weak type alias, or inherent associated type.
     /// All of these types are represented as pairs of def-id and args, and can
     /// be normalized, so they are grouped conceptually.
-    Alias(AliasKind, I::AliasTy),
+    Alias(AliasTyKind, AliasTy<I>),
 
     /// A type parameter; for example, `T` in `fn f<T>(x: T) {}`.
     Param(I::ParamTy),
@@ -341,13 +339,10 @@
     }
 }
 
-// This is manually implemented because a derive would require `I: Eq`
-impl<I: Interner> Eq for TyKind<I> {}
-
 impl<I: Interner> DebugWithInfcx<I> for TyKind<I> {
     fn fmt<Infcx: InferCtxtLike<Interner = I>>(
         this: WithInfcx<'_, Infcx, &Self>,
-        f: &mut core::fmt::Formatter<'_>,
+        f: &mut fmt::Formatter<'_>,
     ) -> fmt::Result {
         match this.data {
             Bool => write!(f, "bool"),
@@ -427,6 +422,154 @@
     }
 }
 
+/// Represents the projection of an associated, opaque, or lazy-type-alias type.
+///
+/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
+/// * For an inherent projection, this would be `Ty::N<...>`.
+/// * For an opaque type, there is no explicit syntax.
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    Hash(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = "")
+)]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))]
+pub struct AliasTy<I: Interner> {
+    /// The parameters of the associated or opaque type.
+    ///
+    /// For a projection, these are the generic parameters for the trait and the
+    /// GAT parameters, if there are any.
+    ///
+    /// For an inherent projection, they consist of the self type and the GAT parameters,
+    /// if there are any.
+    ///
+    /// For RPIT the generic parameters are for the generics of the function,
+    /// while for TAIT it is used for the generic parameters of the alias.
+    pub args: I::GenericArgs,
+
+    /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
+    /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
+    /// this is an opaque.
+    ///
+    /// During codegen, `interner.type_of(def_id)` can be used to get the type of the
+    /// underlying type if the type is an opaque.
+    ///
+    /// Note that if this is an associated type, this is not the `DefId` of the
+    /// `TraitRef` containing this associated type, which is in `interner.associated_item(def_id).container`,
+    /// aka. `interner.parent(def_id)`.
+    pub def_id: I::DefId,
+
+    /// This field exists to prevent the creation of `AliasTy` without using
+    /// [AliasTy::new].
+    pub(crate) _use_alias_ty_new_instead: (),
+}
+
+impl<I: Interner> AliasTy<I> {
+    pub fn new(
+        interner: I,
+        def_id: I::DefId,
+        args: impl IntoIterator<Item: Into<I::GenericArg>>,
+    ) -> AliasTy<I> {
+        let args = interner.check_and_mk_args(def_id, args);
+        AliasTy { def_id, args, _use_alias_ty_new_instead: () }
+    }
+
+    pub fn kind(self, interner: I) -> AliasTyKind {
+        interner.alias_ty_kind(self)
+    }
+
+    /// Whether this alias type is an opaque.
+    pub fn is_opaque(self, interner: I) -> bool {
+        matches!(self.kind(interner), AliasTyKind::Opaque)
+    }
+
+    pub fn to_ty(self, interner: I) -> I::Ty {
+        Ty::new_alias(interner, self.kind(interner), self)
+    }
+}
+
+/// The following methods work only with (trait) associated type projections.
+impl<I: Interner> AliasTy<I> {
+    pub fn self_ty(self) -> I::Ty {
+        self.args.type_at(0)
+    }
+
+    pub fn with_self_ty(self, interner: I, self_ty: I::Ty) -> Self {
+        AliasTy::new(
+            interner,
+            self.def_id,
+            [self_ty.into()].into_iter().chain(self.args.into_iter().skip(1)),
+        )
+    }
+
+    pub fn trait_def_id(self, interner: I) -> I::DefId {
+        assert_eq!(self.kind(interner), AliasTyKind::Projection, "expected a projection");
+        interner.parent(self.def_id)
+    }
+
+    /// Extracts the underlying trait reference and own args from this projection.
+    /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
+    /// then this function would return a `T: StreamingIterator` trait reference and
+    /// `['a]` as the own args.
+    pub fn trait_ref_and_own_args(self, interner: I) -> (ty::TraitRef<I>, I::OwnItemArgs) {
+        debug_assert_eq!(self.kind(interner), AliasTyKind::Projection);
+        interner.trait_ref_and_own_args_for_alias(self.def_id, self.args)
+    }
+
+    /// Extracts the underlying trait reference from this projection.
+    /// For example, if this is a projection of `<T as Iterator>::Item`,
+    /// then this function would return a `T: Iterator` trait reference.
+    ///
+    /// WARNING: This will drop the args for generic associated types
+    /// consider calling [Self::trait_ref_and_own_args] to get those
+    /// as well.
+    pub fn trait_ref(self, interner: I) -> ty::TraitRef<I> {
+        self.trait_ref_and_own_args(interner).0
+    }
+}
+
+/// The following methods work only with inherent associated type projections.
+impl<I: Interner> AliasTy<I> {
+    /// Transform the generic parameters to have the given `impl` args as the base and the GAT args on top of that.
+    ///
+    /// Does the following transformation:
+    ///
+    /// ```text
+    /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
+    ///
+    ///     I_i impl args
+    ///     P_j GAT args
+    /// ```
+    pub fn rebase_inherent_args_onto_impl(
+        self,
+        impl_args: I::GenericArgs,
+        interner: I,
+    ) -> I::GenericArgs {
+        debug_assert_eq!(self.kind(interner), AliasTyKind::Inherent);
+        interner.mk_args_from_iter(impl_args.into_iter().chain(self.args.into_iter().skip(1)))
+    }
+}
+
+impl<I: Interner> fmt::Debug for AliasTy<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        WithInfcx::with_no_infcx(self).fmt(f)
+    }
+}
+impl<I: Interner> DebugWithInfcx<I> for AliasTy<I> {
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
+        f: &mut fmt::Formatter<'_>,
+    ) -> fmt::Result {
+        f.debug_struct("AliasTy")
+            .field("args", &this.map(|data| data.args))
+            .field("def_id", &this.data.def_id)
+            .finish()
+    }
+}
+
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
 pub enum IntTy {
@@ -804,29 +947,124 @@
     Debug(bound = "")
 )]
 #[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic)]
 pub struct TypeAndMut<I: Interner> {
     pub ty: I::Ty,
     pub mutbl: Mutability,
 }
 
-impl<I: Interner> TypeFoldable<I> for TypeAndMut<I>
-where
-    I::Ty: TypeFoldable<I>,
-{
-    fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
-        Ok(TypeAndMut {
-            ty: self.ty.try_fold_with(folder)?,
-            mutbl: self.mutbl.try_fold_with(folder)?,
-        })
+#[derive(derivative::Derivative)]
+#[derivative(
+    Clone(bound = ""),
+    Copy(bound = ""),
+    PartialEq(bound = ""),
+    Eq(bound = ""),
+    Hash(bound = "")
+)]
+#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))]
+#[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)]
+pub struct FnSig<I: Interner> {
+    pub inputs_and_output: I::Tys,
+    pub c_variadic: bool,
+    pub safety: I::Safety,
+    pub abi: I::Abi,
+}
+
+impl<I: Interner> FnSig<I> {
+    pub fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty) {
+        self.inputs_and_output.split_inputs_and_output()
+    }
+
+    pub fn inputs(self) -> I::FnInputTys {
+        self.split_inputs_and_output().0
+    }
+
+    pub fn output(self) -> I::Ty {
+        self.split_inputs_and_output().1
+    }
+
+    pub fn is_fn_trait_compatible(self) -> bool {
+        let FnSig { safety, abi, c_variadic, .. } = self;
+        !c_variadic && safety.is_safe() && abi.is_rust()
     }
 }
 
-impl<I: Interner> TypeVisitable<I> for TypeAndMut<I>
-where
-    I::Ty: TypeVisitable<I>,
-{
-    fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> V::Result {
-        try_visit!(self.ty.visit_with(visitor));
-        self.mutbl.visit_with(visitor)
+impl<I: Interner> ty::Binder<I, FnSig<I>> {
+    #[inline]
+    pub fn inputs(self) -> ty::Binder<I, I::FnInputTys> {
+        self.map_bound(|fn_sig| fn_sig.inputs())
+    }
+
+    #[inline]
+    #[track_caller]
+    pub fn input(self, index: usize) -> ty::Binder<I, I::Ty> {
+        self.map_bound(|fn_sig| fn_sig.inputs()[index])
+    }
+
+    pub fn inputs_and_output(self) -> ty::Binder<I, I::Tys> {
+        self.map_bound(|fn_sig| fn_sig.inputs_and_output)
+    }
+
+    #[inline]
+    pub fn output(self) -> ty::Binder<I, I::Ty> {
+        self.map_bound(|fn_sig| fn_sig.output())
+    }
+
+    pub fn c_variadic(self) -> bool {
+        self.skip_binder().c_variadic
+    }
+
+    pub fn safety(self) -> I::Safety {
+        self.skip_binder().safety
+    }
+
+    pub fn abi(self) -> I::Abi {
+        self.skip_binder().abi
+    }
+
+    pub fn is_fn_trait_compatible(&self) -> bool {
+        self.skip_binder().is_fn_trait_compatible()
+    }
+}
+
+impl<I: Interner> fmt::Debug for FnSig<I> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        WithInfcx::with_no_infcx(self).fmt(f)
+    }
+}
+impl<I: Interner> DebugWithInfcx<I> for FnSig<I> {
+    fn fmt<Infcx: InferCtxtLike<Interner = I>>(
+        this: WithInfcx<'_, Infcx, &Self>,
+        f: &mut fmt::Formatter<'_>,
+    ) -> fmt::Result {
+        let sig = this.data;
+        let FnSig { inputs_and_output: _, c_variadic, safety, abi } = sig;
+
+        write!(f, "{}", safety.prefix_str())?;
+        if !abi.is_rust() {
+            write!(f, "extern \"{abi:?}\" ")?;
+        }
+
+        write!(f, "fn(")?;
+        let (inputs, output) = sig.split_inputs_and_output();
+        for (i, ty) in inputs.iter().enumerate() {
+            if i > 0 {
+                write!(f, ", ")?;
+            }
+            write!(f, "{:?}", &this.wrap(ty))?;
+        }
+        if *c_variadic {
+            if inputs.is_empty() {
+                write!(f, "...")?;
+            } else {
+                write!(f, ", ...")?;
+            }
+        }
+        write!(f, ")")?;
+
+        match output.kind() {
+            Tuple(list) if list.is_empty() => Ok(()),
+            _ => write!(f, " -> {:?}", &this.wrap(sig.output())),
+        }
     }
 }
diff --git a/compiler/rustc_type_ir/src/upcast.rs b/compiler/rustc_type_ir/src/upcast.rs
new file mode 100644
index 0000000..2049337
--- /dev/null
+++ b/compiler/rustc_type_ir/src/upcast.rs
@@ -0,0 +1,24 @@
+/// An `Into`-like trait that takes `TyCtxt` to perform interner-specific transformations.
+pub trait Upcast<I, T> {
+    fn upcast(self, interner: I) -> T;
+}
+
+impl<I, T, U> Upcast<I, U> for T
+where
+    U: UpcastFrom<I, T>,
+{
+    fn upcast(self, interner: I) -> U {
+        U::upcast_from(self, interner)
+    }
+}
+
+/// A `From`-like trait that takes `TyCtxt` to perform interner-specific transformations.
+pub trait UpcastFrom<I, T> {
+    fn upcast_from(from: T, interner: I) -> Self;
+}
+
+impl<I, T> UpcastFrom<I, T> for T {
+    fn upcast_from(from: T, _tcx: I) -> Self {
+        from
+    }
+}
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs
index 2f588c6..6880c7b 100644
--- a/compiler/rustc_type_ir/src/visit.rs
+++ b/compiler/rustc_type_ir/src/visit.rs
@@ -47,7 +47,8 @@
 use std::fmt;
 use std::ops::ControlFlow;
 
-use crate::{self as ty, BoundVars, Interner, IntoKind, Lrc, TypeFlags};
+use crate::inherent::*;
+use crate::{self as ty, Interner, Lrc, TypeFlags};
 
 /// This trait is implemented for every type that can be visited,
 /// providing the skeleton of the traversal.
@@ -89,7 +90,7 @@
     #[cfg(not(feature = "nightly"))]
     type Result: VisitorResult;
 
-    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> Self::Result {
+    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
         t.super_visit_with(self)
     }
 
@@ -375,11 +376,11 @@
 impl<I: Interner> TypeVisitor<I> for HasTypeFlagsVisitor {
     type Result = ControlFlow<FoundFlags>;
 
-    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> Self::Result {
+    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
         // If we're looking for the HAS_BINDER_VARS flag, check if the
         // binder has vars. This won't be present in the binder's bound
         // value, so we need to check here too.
-        if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.has_no_bound_vars() {
+        if self.flags.intersects(TypeFlags::HAS_BINDER_VARS) && !t.bound_vars().is_empty() {
             return ControlFlow::Break(FoundFlags);
         }
 
@@ -475,7 +476,7 @@
 impl<I: Interner> TypeVisitor<I> for HasEscapingVarsVisitor {
     type Result = ControlFlow<FoundEscapingVars>;
 
-    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &I::Binder<T>) -> Self::Result {
+    fn visit_binder<T: TypeVisitable<I>>(&mut self, t: &ty::Binder<I, T>) -> Self::Result {
         self.outer_index.shift_in(1);
         let result = t.super_visit_with(self);
         self.outer_index.shift_out(1);
diff --git a/compiler/rustc_type_ir_macros/Cargo.toml b/compiler/rustc_type_ir_macros/Cargo.toml
new file mode 100644
index 0000000..cb95ca6
--- /dev/null
+++ b/compiler/rustc_type_ir_macros/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "rustc_type_ir_macros"
+version = "0.0.0"
+edition = "2021"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+# tidy-alphabetical-start
+proc-macro2 = "1"
+quote = "1"
+syn = { version = "2.0.9", features = ["full"] }
+synstructure = "0.13.0"
+# tidy-alphabetical-end
diff --git a/compiler/rustc_type_ir_macros/src/lib.rs b/compiler/rustc_type_ir_macros/src/lib.rs
new file mode 100644
index 0000000..000bcf2
--- /dev/null
+++ b/compiler/rustc_type_ir_macros/src/lib.rs
@@ -0,0 +1,159 @@
+use quote::quote;
+use syn::{parse_quote, visit_mut::VisitMut};
+use synstructure::decl_derive;
+
+decl_derive!(
+    [TypeFoldable_Generic] => type_foldable_derive
+);
+decl_derive!(
+    [TypeVisitable_Generic] => type_visitable_derive
+);
+decl_derive!(
+    [Lift_Generic] => lift_derive
+);
+
+fn type_foldable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    if let syn::Data::Union(_) = s.ast().data {
+        panic!("cannot derive on union")
+    }
+
+    if !s.ast().generics.type_params().any(|ty| ty.ident == "I") {
+        s.add_impl_generic(parse_quote! { I });
+    }
+
+    s.add_where_predicate(parse_quote! { I: Interner });
+    s.add_bounds(synstructure::AddBounds::Fields);
+    s.bind_with(|_| synstructure::BindStyle::Move);
+    let body_fold = s.each_variant(|vi| {
+        let bindings = vi.bindings();
+        vi.construct(|_, index| {
+            let bind = &bindings[index];
+            quote! {
+                ::rustc_type_ir::fold::TypeFoldable::try_fold_with(#bind, __folder)?
+            }
+        })
+    });
+
+    s.bound_impl(
+        quote!(::rustc_type_ir::fold::TypeFoldable<I>),
+        quote! {
+            fn try_fold_with<__F: ::rustc_type_ir::fold::FallibleTypeFolder<I>>(
+                self,
+                __folder: &mut __F
+            ) -> Result<Self, __F::Error> {
+                Ok(match self { #body_fold })
+            }
+        },
+    )
+}
+
+fn lift_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    if let syn::Data::Union(_) = s.ast().data {
+        panic!("cannot derive on union")
+    }
+
+    if !s.ast().generics.type_params().any(|ty| ty.ident == "I") {
+        s.add_impl_generic(parse_quote! { I });
+    }
+
+    s.add_bounds(synstructure::AddBounds::None);
+    s.add_where_predicate(parse_quote! { I: Interner });
+    s.add_impl_generic(parse_quote! { J });
+    s.add_where_predicate(parse_quote! { J: Interner });
+
+    let mut wc = vec![];
+    s.bind_with(|_| synstructure::BindStyle::Move);
+    let body_fold = s.each_variant(|vi| {
+        let bindings = vi.bindings();
+        vi.construct(|field, index| {
+            let ty = field.ty.clone();
+            let lifted_ty = lift(ty.clone());
+            wc.push(parse_quote! { #ty: ::rustc_type_ir::lift::Lift<J, Lifted = #lifted_ty> });
+            let bind = &bindings[index];
+            quote! {
+                #bind.lift_to_tcx(interner)?
+            }
+        })
+    });
+    for wc in wc {
+        s.add_where_predicate(wc);
+    }
+
+    let (_, ty_generics, _) = s.ast().generics.split_for_impl();
+    let name = s.ast().ident.clone();
+    let self_ty: syn::Type = parse_quote! { #name #ty_generics };
+    let lifted_ty = lift(self_ty);
+
+    s.bound_impl(
+        quote!(::rustc_type_ir::lift::Lift<J>),
+        quote! {
+            type Lifted = #lifted_ty;
+
+            fn lift_to_tcx(
+                self,
+                interner: J,
+            ) -> Option<Self::Lifted> {
+                Some(match self { #body_fold })
+            }
+        },
+    )
+}
+
+fn lift(mut ty: syn::Type) -> syn::Type {
+    struct ItoJ;
+    impl VisitMut for ItoJ {
+        fn visit_type_path_mut(&mut self, i: &mut syn::TypePath) {
+            if i.qself.is_none() {
+                if let Some(first) = i.path.segments.first_mut() {
+                    if first.ident == "I" {
+                        *first = parse_quote! { J };
+                    }
+                }
+            }
+            syn::visit_mut::visit_type_path_mut(self, i);
+        }
+    }
+
+    ItoJ.visit_type_mut(&mut ty);
+
+    ty
+}
+
+fn type_visitable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    if let syn::Data::Union(_) = s.ast().data {
+        panic!("cannot derive on union")
+    }
+
+    if !s.ast().generics.type_params().any(|ty| ty.ident == "I") {
+        s.add_impl_generic(parse_quote! { I });
+    }
+
+    s.add_where_predicate(parse_quote! { I: Interner });
+    s.add_bounds(synstructure::AddBounds::Fields);
+    let body_visit = s.each(|bind| {
+        quote! {
+            match ::rustc_ast_ir::visit::VisitorResult::branch(
+                ::rustc_type_ir::visit::TypeVisitable::visit_with(#bind, __visitor)
+            ) {
+                ::core::ops::ControlFlow::Continue(()) => {},
+                ::core::ops::ControlFlow::Break(r) => {
+                    return ::rustc_ast_ir::visit::VisitorResult::from_residual(r);
+                },
+            }
+        }
+    });
+    s.bind_with(|_| synstructure::BindStyle::Move);
+
+    s.bound_impl(
+        quote!(::rustc_type_ir::visit::TypeVisitable<I>),
+        quote! {
+            fn visit_with<__V: ::rustc_type_ir::visit::TypeVisitor<I>>(
+                &self,
+                __visitor: &mut __V
+            ) -> __V::Result {
+                match *self { #body_visit }
+                <__V::Result as ::rustc_ast_ir::visit::VisitorResult>::output()
+            }
+        },
+    )
+}
diff --git a/compiler/stable_mir/src/abi.rs b/compiler/stable_mir/src/abi.rs
index 92bc2e3..e1c14fe 100644
--- a/compiler/stable_mir/src/abi.rs
+++ b/compiler/stable_mir/src/abi.rs
@@ -6,7 +6,7 @@
 use crate::Error;
 use crate::Opaque;
 use std::fmt::{self, Debug};
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 use std::ops::RangeInclusive;
 
 /// A function ABI definition.
@@ -133,7 +133,7 @@
     Primitive,
 
     /// All fields start at no offset. The `usize` is the field count.
-    Union(NonZeroUsize),
+    Union(NonZero<usize>),
 
     /// Array/vector-like placement, with all fields of identical types.
     Array { stride: Size, count: u64 },
diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs
index e077c58..a1432ac 100644
--- a/compiler/stable_mir/src/mir/body.rs
+++ b/compiler/stable_mir/src/mir/body.rs
@@ -915,8 +915,8 @@
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 pub enum Safety {
+    Safe,
     Unsafe,
-    Normal,
 }
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
diff --git a/compiler/stable_mir/src/ty.rs b/compiler/stable_mir/src/ty.rs
index bc6fb34..321c56b 100644
--- a/compiler/stable_mir/src/ty.rs
+++ b/compiler/stable_mir/src/ty.rs
@@ -1,6 +1,5 @@
 use super::{
-    mir::Safety,
-    mir::{Body, Mutability},
+    mir::{Body, Mutability, Safety},
     with, DefId, Error, Symbol,
 };
 use crate::abi::Layout;
@@ -897,13 +896,19 @@
     pub args: GenericArgs,
 }
 
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct AliasTerm {
+    pub def_id: AliasDef,
+    pub args: GenericArgs,
+}
+
 pub type PolyFnSig = Binder<FnSig>;
 
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct FnSig {
     pub inputs_and_output: Vec<Ty>,
     pub c_variadic: bool,
-    pub unsafety: Safety,
+    pub safety: Safety,
     pub abi: Abi,
 }
 
@@ -1194,12 +1199,13 @@
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct TraitDecl {
     pub def_id: TraitDef,
-    pub unsafety: Safety,
+    pub safety: Safety,
     pub paren_sugar: bool,
     pub has_auto_impl: bool,
     pub is_marker: bool,
     pub is_coinductive: bool,
     pub skip_array_during_method_dispatch: bool,
+    pub skip_boxed_slice_during_method_dispatch: bool,
     pub specialization_kind: TraitSpecializationKind,
     pub must_implement_one_of: Option<Vec<Ident>>,
     pub implement_via_object: bool,
@@ -1350,7 +1356,7 @@
 
 #[derive(Clone, Debug, Eq, PartialEq)]
 pub struct ProjectionPredicate {
-    pub projection_ty: AliasTy,
+    pub projection_term: AliasTerm,
     pub term: TermKind,
 }
 
diff --git a/config.example.toml b/config.example.toml
index 3b76952..2285217 100644
--- a/config.example.toml
+++ b/config.example.toml
@@ -213,17 +213,17 @@
 # the root of the repository.
 #build-dir = "build"
 
-# Instead of downloading the src/stage0.json version of Cargo specified, use
+# Instead of downloading the src/stage0 version of Cargo specified, use
 # this Cargo binary instead to build all Rust code
 # If you set this, you likely want to set `rustc` as well.
 #cargo = "/path/to/cargo"
 
-# Instead of downloading the src/stage0.json version of the compiler
+# Instead of downloading the src/stage0 version of the compiler
 # specified, use this rustc binary instead as the stage0 snapshot compiler.
 # If you set this, you likely want to set `cargo` as well.
 #rustc = "/path/to/rustc"
 
-# Instead of downloading the src/stage0.json version of rustfmt specified,
+# Instead of downloading the src/stage0 version of rustfmt specified,
 # use this rustfmt binary instead as the stage0 snapshot rustfmt.
 #rustfmt = "/path/to/rustfmt"
 
@@ -653,9 +653,12 @@
 # when no explicit backend is specified.
 #codegen-backends = ["llvm"]
 
-# Indicates whether LLD will be compiled and made available in the sysroot for
-# rustc to execute.
-#lld = false
+# Indicates whether LLD will be compiled and made available in the sysroot for rustc to execute, and
+# whether to set it as rustc's default linker on `x86_64-unknown-linux-gnu`. This will also only be
+# when *not* building an external LLVM (so only when using `download-ci-llvm` or building LLVM from
+# the in-tree source): setting `llvm-config` in the `[target.x86_64-unknown-linux-gnu]` section will
+# make this default to false. 
+#lld = false in all cases, except on `x86_64-unknown-linux-gnu` as described above, where it is true
 
 # Indicates whether LLD will be used to link Rust crates during bootstrap on
 # supported platforms.
diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml
index e8afed6..2e7fcb9 100644
--- a/library/alloc/Cargo.toml
+++ b/library/alloc/Cargo.toml
@@ -37,4 +37,6 @@
 compiler-builtins-mangled-names = ["compiler_builtins/mangled-names"]
 compiler-builtins-weak-intrinsics = ["compiler_builtins/weak-intrinsics"]
 # Make panics and failed asserts immediately abort without formatting any message
-panic_immediate_abort = []
+panic_immediate_abort = ["core/panic_immediate_abort"]
+# Choose algorithms that are optimized for binary size instead of runtime performance
+optimize_for_size = ["core/optimize_for_size"]
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index e5d6244..21d0050 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -135,6 +135,45 @@
 //! is not allowed. For more guidance on working with box from unsafe code, see
 //! [rust-lang/unsafe-code-guidelines#326][ucg#326].
 //!
+//! # Editions
+//!
+//! A special case exists for the implementation of `IntoIterator` for arrays on the Rust 2021
+//! edition, as documented [here][array]. Unfortunately, it was later found that a similar
+//! workaround should be added for boxed slices, and this was applied in the 2024 edition.
+//!
+//! Specifically, `IntoIterator` is implemented for `Box<[T]>` on all editions, but specific calls
+//! to `into_iter()` for boxed slices will defer to the slice implementation on editions before
+//! 2024:
+//!
+#![cfg_attr(bootstrap, doc = "```rust,edition2021,ignore")]
+#![cfg_attr(not(bootstrap), doc = "```rust,edition2021")]
+//! // Rust 2015, 2018, and 2021:
+//!
+//! # #![allow(boxed_slice_into_iter)] // override our `deny(warnings)`
+//! let boxed_slice: Box<[i32]> = vec![0; 3].into_boxed_slice();
+//!
+//! // This creates a slice iterator, producing references to each value.
+//! for item in boxed_slice.into_iter().enumerate() {
+//!     let (i, x): (usize, &i32) = item;
+//!     println!("boxed_slice[{i}] = {x}");
+//! }
+//!
+//! // The `boxed_slice_into_iter` lint suggests this change for future compatibility:
+//! for item in boxed_slice.iter().enumerate() {
+//!     let (i, x): (usize, &i32) = item;
+//!     println!("boxed_slice[{i}] = {x}");
+//! }
+//!
+//! // You can explicitly iterate a boxed slice by value using `IntoIterator::into_iter`
+//! for item in IntoIterator::into_iter(boxed_slice).enumerate() {
+//!     let (i, x): (usize, i32) = item;
+//!     println!("boxed_slice[{i}] = {x}");
+//! }
+//! ```
+//!
+//! Similar to the array implementation, this may be modified in the future to remove this override,
+//! and it's best to avoid relying on this edition-dependent behavior if you wish to preserve
+//! compatibility with future versions of the compiler.
 //!
 //! [ucg#198]: https://github.com/rust-lang/unsafe-code-guidelines/issues/198
 //! [ucg#326]: https://github.com/rust-lang/unsafe-code-guidelines/issues/326
@@ -165,6 +204,7 @@
 };
 use core::pin::Pin;
 use core::ptr::{self, addr_of_mut, NonNull, Unique};
+use core::slice;
 use core::task::{Context, Poll};
 
 #[cfg(not(no_global_oom_handling))]
@@ -177,6 +217,7 @@
 use crate::str::from_boxed_utf8_unchecked;
 #[cfg(not(no_global_oom_handling))]
 use crate::string::String;
+use crate::vec;
 #[cfg(not(no_global_oom_handling))]
 use crate::vec::Vec;
 
@@ -2080,6 +2121,99 @@
     }
 }
 
+/// This implementation is required to make sure that the `Box<[I]>: IntoIterator`
+/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
+#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<I, A: Allocator> !Iterator for Box<[I], A> {}
+
+/// This implementation is required to make sure that the `&Box<[I]>: IntoIterator`
+/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
+#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<'a, I, A: Allocator> !Iterator for &'a Box<[I], A> {}
+
+/// This implementation is required to make sure that the `&mut Box<[I]>: IntoIterator`
+/// implementation doesn't overlap with `IntoIterator for T where T: Iterator` blanket.
+#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<'a, I, A: Allocator> !Iterator for &'a mut Box<[I], A> {}
+
+// Note: the `#[rustc_skip_during_method_dispatch(boxed_slice)]` on `trait IntoIterator`
+// hides this implementation from explicit `.into_iter()` calls on editions < 2024,
+// so those calls will still resolve to the slice implementation, by reference.
+#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<I, A: Allocator> IntoIterator for Box<[I], A> {
+    type IntoIter = vec::IntoIter<I, A>;
+    type Item = I;
+    fn into_iter(self) -> vec::IntoIter<I, A> {
+        self.into_vec().into_iter()
+    }
+}
+
+#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<'a, I, A: Allocator> IntoIterator for &'a Box<[I], A> {
+    type IntoIter = slice::Iter<'a, I>;
+    type Item = &'a I;
+    fn into_iter(self) -> slice::Iter<'a, I> {
+        self.iter()
+    }
+}
+
+#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<'a, I, A: Allocator> IntoIterator for &'a mut Box<[I], A> {
+    type IntoIter = slice::IterMut<'a, I>;
+    type Item = &'a mut I;
+    fn into_iter(self) -> slice::IterMut<'a, I> {
+        self.iter_mut()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")]
+impl FromIterator<char> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<'a> FromIterator<&'a char> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<'a> FromIterator<&'a str> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")]
+impl FromIterator<String> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<A: Allocator> FromIterator<Box<str, A>> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = Box<str, A>>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "boxed_str_from_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<'a> FromIterator<Cow<'a, str>> for Box<str> {
+    fn from_iter<T: IntoIterator<Item = Cow<'a, str>>>(iter: T) -> Self {
+        String::from_iter(iter).into_boxed_str()
+    }
+}
+
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_slice_clone", since = "1.3.0")]
 impl<T: Clone, A: Allocator + Clone> Clone for Box<[T], A> {
diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs
index f143e55..b13af93 100644
--- a/library/alloc/src/ffi/c_str.rs
+++ b/library/alloc/src/ffi/c_str.rs
@@ -910,6 +910,19 @@
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
+impl Default for Rc<CStr> {
+    /// Creates an empty CStr inside an Rc
+    ///
+    /// This may or may not share an allocation with other Rcs on the same thread.
+    #[inline]
+    fn default() -> Self {
+        let c_str: &CStr = Default::default();
+        Rc::from(c_str)
+    }
+}
+
 #[cfg(not(test))]
 #[stable(feature = "default_box_extra", since = "1.17.0")]
 impl Default for Box<CStr> {
diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs
index b991875..ae44cab 100644
--- a/library/alloc/src/fmt.rs
+++ b/library/alloc/src/fmt.rs
@@ -403,7 +403,7 @@
 //! is, a formatting implementation must and may only return an error if the
 //! passed-in [`Formatter`] returns an error. This is because, contrary to what
 //! the function signature might suggest, string formatting is an infallible
-//! operation. This function only returns a result because writing to the
+//! operation. This function only returns a [`Result`] because writing to the
 //! underlying stream might fail and it must provide a way to propagate the fact
 //! that an error has occurred back up the stack.
 //!
@@ -630,7 +630,9 @@
     fn format_inner(args: Arguments<'_>) -> string::String {
         let capacity = args.estimated_capacity();
         let mut output = string::String::with_capacity(capacity);
-        output.write_fmt(args).expect("a formatting trait implementation returned an error");
+        output
+            .write_fmt(args)
+            .expect("a formatting trait implementation returned an error when the underlying stream did not");
         output
     }
 
diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs
index 91b83cf..4ac0c9b 100644
--- a/library/alloc/src/lib.rs
+++ b/library/alloc/src/lib.rs
@@ -160,6 +160,7 @@
 #![feature(tuple_trait)]
 #![feature(unicode_internals)]
 #![feature(unsize)]
+#![feature(unwrap_infallible)]
 #![feature(vec_pop_if)]
 // tidy-alphabetical-end
 //
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index c245b42..875c24c 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -366,6 +366,12 @@
     }
 
     #[inline]
+    fn into_inner_with_allocator(this: Self) -> (NonNull<RcBox<T>>, A) {
+        let this = mem::ManuallyDrop::new(this);
+        (this.ptr, unsafe { ptr::read(&this.alloc) })
+    }
+
+    #[inline]
     unsafe fn from_inner_in(ptr: NonNull<RcBox<T>>, alloc: A) -> Self {
         Self { ptr, phantom: PhantomData, alloc }
     }
@@ -1145,12 +1151,9 @@
     /// ```
     #[unstable(feature = "new_uninit", issue = "63291")]
     #[inline]
-    pub unsafe fn assume_init(self) -> Rc<T, A>
-    where
-        A: Clone,
-    {
-        let md_self = mem::ManuallyDrop::new(self);
-        unsafe { Rc::from_inner_in(md_self.ptr.cast(), md_self.alloc.clone()) }
+    pub unsafe fn assume_init(self) -> Rc<T, A> {
+        let (ptr, alloc) = Rc::into_inner_with_allocator(self);
+        unsafe { Rc::from_inner_in(ptr.cast(), alloc) }
     }
 }
 
@@ -1189,12 +1192,9 @@
     /// ```
     #[unstable(feature = "new_uninit", issue = "63291")]
     #[inline]
-    pub unsafe fn assume_init(self) -> Rc<[T], A>
-    where
-        A: Clone,
-    {
-        let md_self = mem::ManuallyDrop::new(self);
-        unsafe { Rc::from_ptr_in(md_self.ptr.as_ptr() as _, md_self.alloc.clone()) }
+    pub unsafe fn assume_init(self) -> Rc<[T], A> {
+        let (ptr, alloc) = Rc::into_inner_with_allocator(self);
+        unsafe { Rc::from_ptr_in(ptr.as_ptr() as _, alloc) }
     }
 }
 
@@ -1356,6 +1356,33 @@
         ptr
     }
 
+    /// Consumes the `Rc`, returning the wrapped pointer and allocator.
+    ///
+    /// To avoid a memory leak the pointer must be converted back to an `Rc` using
+    /// [`Rc::from_raw_in`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api)]
+    /// use std::rc::Rc;
+    /// use std::alloc::System;
+    ///
+    /// let x = Rc::new_in("hello".to_owned(), System);
+    /// let (ptr, alloc) = Rc::into_raw_with_allocator(x);
+    /// assert_eq!(unsafe { &*ptr }, "hello");
+    /// let x = unsafe { Rc::from_raw_in(ptr, alloc) };
+    /// assert_eq!(&*x, "hello");
+    /// ```
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
+        let this = mem::ManuallyDrop::new(this);
+        let ptr = Self::as_ptr(&this);
+        // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
+        let alloc = unsafe { ptr::read(&this.alloc) };
+        (ptr, alloc)
+    }
+
     /// Provides a raw pointer to the data.
     ///
     /// The counts are not affected in any way and the `Rc` is not consumed. The pointer is valid
@@ -1809,7 +1836,9 @@
         // reference to the allocation.
         unsafe { &mut this.ptr.as_mut().value }
     }
+}
 
+impl<T: Clone, A: Allocator> Rc<T, A> {
     /// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the
     /// clone.
     ///
@@ -1845,7 +1874,7 @@
     }
 }
 
-impl<A: Allocator + Clone> Rc<dyn Any, A> {
+impl<A: Allocator> Rc<dyn Any, A> {
     /// Attempt to downcast the `Rc<dyn Any>` to a concrete type.
     ///
     /// # Examples
@@ -1869,10 +1898,8 @@
     pub fn downcast<T: Any>(self) -> Result<Rc<T, A>, Self> {
         if (*self).is::<T>() {
             unsafe {
-                let ptr = self.ptr.cast::<RcBox<T>>();
-                let alloc = self.alloc.clone();
-                forget(self);
-                Ok(Rc::from_inner_in(ptr, alloc))
+                let (ptr, alloc) = Rc::into_inner_with_allocator(self);
+                Ok(Rc::from_inner_in(ptr.cast(), alloc))
             }
         } else {
             Err(self)
@@ -1909,10 +1936,8 @@
     #[unstable(feature = "downcast_unchecked", issue = "90850")]
     pub unsafe fn downcast_unchecked<T: Any>(self) -> Rc<T, A> {
         unsafe {
-            let ptr = self.ptr.cast::<RcBox<T>>();
-            let alloc = self.alloc.clone();
-            mem::forget(self);
-            Rc::from_inner_in(ptr, alloc)
+            let (ptr, alloc) = Rc::into_inner_with_allocator(self);
+            Rc::from_inner_in(ptr.cast(), alloc)
         }
     }
 }
@@ -2226,6 +2251,31 @@
     }
 }
 
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
+impl Default for Rc<str> {
+    /// Creates an empty str inside an Rc
+    ///
+    /// This may or may not share an allocation with other Rcs on the same thread.
+    #[inline]
+    fn default() -> Self {
+        Rc::from("")
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
+impl<T> Default for Rc<[T]> {
+    /// Creates an empty `[T]` inside an Rc
+    ///
+    /// This may or may not share an allocation with other Rcs on the same thread.
+    #[inline]
+    fn default() -> Self {
+        let arr: [T; 0] = [];
+        Rc::from(arr)
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 trait RcEqIdent<T: ?Sized + PartialEq, A: Allocator> {
     fn eq(&self, other: &Rc<T, A>) -> bool;
@@ -2661,12 +2711,13 @@
 }
 
 #[stable(feature = "boxed_slice_try_from", since = "1.43.0")]
-impl<T, const N: usize> TryFrom<Rc<[T]>> for Rc<[T; N]> {
-    type Error = Rc<[T]>;
+impl<T, A: Allocator, const N: usize> TryFrom<Rc<[T], A>> for Rc<[T; N], A> {
+    type Error = Rc<[T], A>;
 
-    fn try_from(boxed_slice: Rc<[T]>) -> Result<Self, Self::Error> {
+    fn try_from(boxed_slice: Rc<[T], A>) -> Result<Self, Self::Error> {
         if boxed_slice.len() == N {
-            Ok(unsafe { Rc::from_raw(Rc::into_raw(boxed_slice) as *mut [T; N]) })
+            let (ptr, alloc) = Rc::into_inner_with_allocator(boxed_slice);
+            Ok(unsafe { Rc::from_inner_in(ptr.cast(), alloc) })
         } else {
             Err(boxed_slice)
         }
@@ -3000,11 +3051,11 @@
         result
     }
 
-    /// Consumes the `Weak<T>` and turns it into a raw pointer.
+    /// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
     ///
     /// This converts the weak pointer into a raw pointer, while still preserving the ownership of
     /// one weak reference (the weak count is not modified by this operation). It can be turned
-    /// back into the `Weak<T>` with [`from_raw`].
+    /// back into the `Weak<T>` with [`from_raw_in`].
     ///
     /// The same restrictions of accessing the target of the pointer as with
     /// [`as_ptr`] apply.
@@ -3012,27 +3063,30 @@
     /// # Examples
     ///
     /// ```
+    /// #![feature(allocator_api)]
     /// use std::rc::{Rc, Weak};
+    /// use std::alloc::System;
     ///
-    /// let strong = Rc::new("hello".to_owned());
+    /// let strong = Rc::new_in("hello".to_owned(), System);
     /// let weak = Rc::downgrade(&strong);
-    /// let raw = weak.into_raw();
+    /// let (raw, alloc) = weak.into_raw_with_allocator();
     ///
     /// assert_eq!(1, Rc::weak_count(&strong));
     /// assert_eq!("hello", unsafe { &*raw });
     ///
-    /// drop(unsafe { Weak::from_raw(raw) });
+    /// drop(unsafe { Weak::from_raw_in(raw, alloc) });
     /// assert_eq!(0, Rc::weak_count(&strong));
     /// ```
     ///
-    /// [`from_raw`]: Weak::from_raw
+    /// [`from_raw_in`]: Weak::from_raw_in
     /// [`as_ptr`]: Weak::as_ptr
     #[inline]
     #[unstable(feature = "allocator_api", issue = "32838")]
-    pub fn into_raw_and_alloc(self) -> (*const T, A) {
-        let rc = mem::ManuallyDrop::new(self);
-        let result = rc.as_ptr();
-        let alloc = unsafe { ptr::read(&rc.alloc) };
+    pub fn into_raw_with_allocator(self) -> (*const T, A) {
+        let this = mem::ManuallyDrop::new(self);
+        let result = this.as_ptr();
+        // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
+        let alloc = unsafe { ptr::read(&this.alloc) };
         (result, alloc)
     }
 
diff --git a/library/alloc/src/str.rs b/library/alloc/src/str.rs
index c0d292c..3e23612 100644
--- a/library/alloc/src/str.rs
+++ b/library/alloc/src/str.rs
@@ -375,14 +375,16 @@
         // Safety: We have written only valid ASCII to our vec
         let mut s = unsafe { String::from_utf8_unchecked(out) };
 
-        for (i, c) in rest[..].char_indices() {
+        for (i, c) in rest.char_indices() {
             if c == 'Σ' {
                 // Σ maps to σ, except at the end of a word where it maps to ς.
                 // This is the only conditional (contextual) but language-independent mapping
                 // in `SpecialCasing.txt`,
                 // so hard-code it rather than have a generic "condition" mechanism.
                 // See https://github.com/rust-lang/rust/issues/26035
-                map_uppercase_sigma(rest, i, &mut s)
+                let out_len = self.len() - rest.len();
+                let sigma_lowercase = map_uppercase_sigma(&self, i + out_len);
+                s.push(sigma_lowercase);
             } else {
                 match conversions::to_lower(c) {
                     [a, '\0', _] => s.push(a),
@@ -400,13 +402,13 @@
         }
         return s;
 
-        fn map_uppercase_sigma(from: &str, i: usize, to: &mut String) {
+        fn map_uppercase_sigma(from: &str, i: usize) -> char {
             // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992
             // for the definition of `Final_Sigma`.
             debug_assert!('Σ'.len_utf8() == 2);
             let is_word_final = case_ignorable_then_cased(from[..i].chars().rev())
                 && !case_ignorable_then_cased(from[i + 2..].chars());
-            to.push_str(if is_word_final { "ς" } else { "σ" });
+            if is_word_final { 'ς' } else { 'σ' }
         }
 
         fn case_ignorable_then_cased<I: Iterator<Item = char>>(iter: I) -> bool {
diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs
index 2a859ad..36078da 100644
--- a/library/alloc/src/string.rs
+++ b/library/alloc/src/string.rs
@@ -60,6 +60,8 @@
 use core::str::pattern::Pattern;
 
 #[cfg(not(no_global_oom_handling))]
+use crate::alloc::Allocator;
+#[cfg(not(no_global_oom_handling))]
 use crate::borrow::{Cow, ToOwned};
 use crate::boxed::Box;
 use crate::collections::TryReserveError;
@@ -1940,8 +1942,10 @@
 
     /// Converts this `String` into a <code>[Box]<[str]></code>.
     ///
-    /// This will drop any excess capacity.
+    /// Before doing the conversion, this method discards excess capacity like [`shrink_to_fit`].
+    /// Note that this call may reallocate and copy the bytes of the string.
     ///
+    /// [`shrink_to_fit`]: String::shrink_to_fit
     /// [str]: prim@str "str"
     ///
     /// # Examples
@@ -1967,10 +1971,10 @@
     /// this function is ideally used for data that lives for the remainder of the program's life,
     /// as dropping the returned reference will cause a memory leak.
     ///
-    /// It does not reallocate or shrink the `String`,
-    /// so the leaked allocation may include unused capacity that is not part
-    /// of the returned slice. If you don't want that, call [`into_boxed_str`],
-    /// and then [`Box::leak`].
+    /// It does not reallocate or shrink the `String`, so the leaked allocation may include unused
+    /// capacity that is not part of the returned slice. If you want to discard excess capacity,
+    /// call [`into_boxed_str`], and then [`Box::leak`] instead. However, keep in mind that
+    /// trimming the capacity may result in a reallocation and copy.
     ///
     /// [`into_boxed_str`]: Self::into_boxed_str
     ///
@@ -2155,8 +2159,8 @@
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_str2", since = "1.45.0")]
-impl FromIterator<Box<str>> for String {
-    fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> String {
+impl<A: Allocator> FromIterator<Box<str, A>> for String {
+    fn from_iter<I: IntoIterator<Item = Box<str, A>>>(iter: I) -> String {
         let mut buf = String::new();
         buf.extend(iter);
         buf
@@ -2237,8 +2241,8 @@
 
 #[cfg(not(no_global_oom_handling))]
 #[stable(feature = "box_str2", since = "1.45.0")]
-impl Extend<Box<str>> for String {
-    fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) {
+impl<A: Allocator> Extend<Box<str, A>> for String {
+    fn extend<I: IntoIterator<Item = Box<str, A>>>(&mut self, iter: I) {
         iter.into_iter().for_each(move |s| self.push_str(&s));
     }
 }
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index 297a273..7dcaa59 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -280,8 +280,8 @@
 
 impl<T: ?Sized, A: Allocator> Arc<T, A> {
     #[inline]
-    fn internal_into_inner_with_allocator(self) -> (NonNull<ArcInner<T>>, A) {
-        let this = mem::ManuallyDrop::new(self);
+    fn into_inner_with_allocator(this: Self) -> (NonNull<ArcInner<T>>, A) {
+        let this = mem::ManuallyDrop::new(this);
         (this.ptr, unsafe { ptr::read(&this.alloc) })
     }
 
@@ -1290,7 +1290,7 @@
     #[must_use = "`self` will be dropped if the result is not used"]
     #[inline]
     pub unsafe fn assume_init(self) -> Arc<T, A> {
-        let (ptr, alloc) = self.internal_into_inner_with_allocator();
+        let (ptr, alloc) = Arc::into_inner_with_allocator(self);
         unsafe { Arc::from_inner_in(ptr.cast(), alloc) }
     }
 }
@@ -1332,7 +1332,7 @@
     #[must_use = "`self` will be dropped if the result is not used"]
     #[inline]
     pub unsafe fn assume_init(self) -> Arc<[T], A> {
-        let (ptr, alloc) = self.internal_into_inner_with_allocator();
+        let (ptr, alloc) = Arc::into_inner_with_allocator(self);
         unsafe { Arc::from_ptr_in(ptr.as_ptr() as _, alloc) }
     }
 }
@@ -1496,6 +1496,34 @@
         ptr
     }
 
+    /// Consumes the `Arc`, returning the wrapped pointer and allocator.
+    ///
+    /// To avoid a memory leak the pointer must be converted back to an `Arc` using
+    /// [`Arc::from_raw_in`].
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api)]
+    /// use std::sync::Arc;
+    /// use std::alloc::System;
+    ///
+    /// let x = Arc::new_in("hello".to_owned(), System);
+    /// let (ptr, alloc) = Arc::into_raw_with_allocator(x);
+    /// assert_eq!(unsafe { &*ptr }, "hello");
+    /// let x = unsafe { Arc::from_raw_in(ptr, alloc) };
+    /// assert_eq!(&*x, "hello");
+    /// ```
+    #[must_use = "losing the pointer will leak memory"]
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub fn into_raw_with_allocator(this: Self) -> (*const T, A) {
+        let this = mem::ManuallyDrop::new(this);
+        let ptr = Self::as_ptr(&this);
+        // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
+        let alloc = unsafe { ptr::read(&this.alloc) };
+        (ptr, alloc)
+    }
+
     /// Provides a raw pointer to the data.
     ///
     /// The counts are not affected in any way and the `Arc` is not consumed. The pointer is valid for
@@ -2227,7 +2255,9 @@
         // either unique to begin with, or became one upon cloning the contents.
         unsafe { Self::get_mut_unchecked(this) }
     }
+}
 
+impl<T: Clone, A: Allocator> Arc<T, A> {
     /// If we have the only reference to `T` then unwrap it. Otherwise, clone `T` and return the
     /// clone.
     ///
@@ -2466,6 +2496,14 @@
         // [2]: (https://github.com/rust-lang/rust/pull/41714)
         acquire!(self.inner().strong);
 
+        // Make sure we aren't trying to "drop" the shared static for empty slices
+        // used by Default::default.
+        debug_assert!(
+            !ptr::addr_eq(self.ptr.as_ptr(), &STATIC_INNER_SLICE.inner),
+            "Arcs backed by a static should never reach a strong count of 0. \
+            Likely decrement_strong_count or from_raw were called too many times.",
+        );
+
         unsafe {
             self.drop_slow();
         }
@@ -2499,7 +2537,7 @@
     {
         if (*self).is::<T>() {
             unsafe {
-                let (ptr, alloc) = self.internal_into_inner_with_allocator();
+                let (ptr, alloc) = Arc::into_inner_with_allocator(self);
                 Ok(Arc::from_inner_in(ptr.cast(), alloc))
             }
         } else {
@@ -2540,7 +2578,7 @@
         T: Any + Send + Sync,
     {
         unsafe {
-            let (ptr, alloc) = self.internal_into_inner_with_allocator();
+            let (ptr, alloc) = Arc::into_inner_with_allocator(self);
             Arc::from_inner_in(ptr.cast(), alloc)
         }
     }
@@ -2738,6 +2776,45 @@
         result
     }
 
+    /// Consumes the `Weak<T>`, returning the wrapped pointer and allocator.
+    ///
+    /// This converts the weak pointer into a raw pointer, while still preserving the ownership of
+    /// one weak reference (the weak count is not modified by this operation). It can be turned
+    /// back into the `Weak<T>` with [`from_raw_in`].
+    ///
+    /// The same restrictions of accessing the target of the pointer as with
+    /// [`as_ptr`] apply.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api)]
+    /// use std::sync::{Arc, Weak};
+    /// use std::alloc::System;
+    ///
+    /// let strong = Arc::new_in("hello".to_owned(), System);
+    /// let weak = Arc::downgrade(&strong);
+    /// let (raw, alloc) = weak.into_raw_with_allocator();
+    ///
+    /// assert_eq!(1, Arc::weak_count(&strong));
+    /// assert_eq!("hello", unsafe { &*raw });
+    ///
+    /// drop(unsafe { Weak::from_raw_in(raw, alloc) });
+    /// assert_eq!(0, Arc::weak_count(&strong));
+    /// ```
+    ///
+    /// [`from_raw_in`]: Weak::from_raw_in
+    /// [`as_ptr`]: Weak::as_ptr
+    #[must_use = "losing the pointer will leak memory"]
+    #[unstable(feature = "allocator_api", issue = "32838")]
+    pub fn into_raw_with_allocator(self) -> (*const T, A) {
+        let this = mem::ManuallyDrop::new(self);
+        let result = this.as_ptr();
+        // Safety: `this` is ManuallyDrop so the allocator will not be double-dropped
+        let alloc = unsafe { ptr::read(&this.alloc) };
+        (result, alloc)
+    }
+
     /// Converts a raw pointer previously created by [`into_raw`] back into `Weak<T>` in the provided
     /// allocator.
     ///
@@ -3057,6 +3134,15 @@
 
         if inner.weak.fetch_sub(1, Release) == 1 {
             acquire!(inner.weak);
+
+            // Make sure we aren't trying to "deallocate" the shared static for empty slices
+            // used by Default::default.
+            debug_assert!(
+                !ptr::addr_eq(self.ptr.as_ptr(), &STATIC_INNER_SLICE.inner),
+                "Arc/Weaks backed by a static should never be deallocated. \
+                Likely decrement_strong_count or from_raw were called too many times.",
+            );
+
             unsafe {
                 self.alloc.deallocate(self.ptr.cast(), Layout::for_value_raw(self.ptr.as_ptr()))
             }
@@ -3298,6 +3384,89 @@
     }
 }
 
+/// Struct to hold the static `ArcInner` used for empty `Arc<str/CStr/[T]>` as
+/// returned by `Default::default`.
+///
+/// Layout notes:
+/// * `repr(align(16))` so we can use it for `[T]` with `align_of::<T>() <= 16`.
+/// * `repr(C)` so `inner` is at offset 0 (and thus guaranteed to actually be aligned to 16).
+/// * `[u8; 1]` (to be initialized with 0) so it can be used for `Arc<CStr>`.
+#[repr(C, align(16))]
+struct SliceArcInnerForStatic {
+    inner: ArcInner<[u8; 1]>,
+}
+#[cfg(not(no_global_oom_handling))]
+const MAX_STATIC_INNER_SLICE_ALIGNMENT: usize = 16;
+
+static STATIC_INNER_SLICE: SliceArcInnerForStatic = SliceArcInnerForStatic {
+    inner: ArcInner {
+        strong: atomic::AtomicUsize::new(1),
+        weak: atomic::AtomicUsize::new(1),
+        data: [0],
+    },
+};
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
+impl Default for Arc<str> {
+    /// Creates an empty str inside an Arc
+    ///
+    /// This may or may not share an allocation with other Arcs.
+    #[inline]
+    fn default() -> Self {
+        let arc: Arc<[u8]> = Default::default();
+        debug_assert!(core::str::from_utf8(&*arc).is_ok());
+        let (ptr, alloc) = Arc::into_inner_with_allocator(arc);
+        unsafe { Arc::from_ptr_in(ptr.as_ptr() as *mut ArcInner<str>, alloc) }
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
+impl Default for Arc<core::ffi::CStr> {
+    /// Creates an empty CStr inside an Arc
+    ///
+    /// This may or may not share an allocation with other Arcs.
+    #[inline]
+    fn default() -> Self {
+        use core::ffi::CStr;
+        let inner: NonNull<ArcInner<[u8]>> = NonNull::from(&STATIC_INNER_SLICE.inner);
+        let inner: NonNull<ArcInner<CStr>> =
+            NonNull::new(inner.as_ptr() as *mut ArcInner<CStr>).unwrap();
+        // `this` semantically is the Arc "owned" by the static, so make sure not to drop it.
+        let this: mem::ManuallyDrop<Arc<CStr>> =
+            unsafe { mem::ManuallyDrop::new(Arc::from_inner(inner)) };
+        (*this).clone()
+    }
+}
+
+#[cfg(not(no_global_oom_handling))]
+#[stable(feature = "more_rc_default_impls", since = "CURRENT_RUSTC_VERSION")]
+impl<T> Default for Arc<[T]> {
+    /// Creates an empty `[T]` inside an Arc
+    ///
+    /// This may or may not share an allocation with other Arcs.
+    #[inline]
+    fn default() -> Self {
+        if mem::align_of::<T>() <= MAX_STATIC_INNER_SLICE_ALIGNMENT {
+            // We take a reference to the whole struct instead of the ArcInner<[u8; 1]> inside it so
+            // we don't shrink the range of bytes the ptr is allowed to access under Stacked Borrows.
+            // (Miri complains on 32-bit targets with Arc<[Align16]> otherwise.)
+            // (Note that NonNull::from(&STATIC_INNER_SLICE.inner) is fine under Tree Borrows.)
+            let inner: NonNull<SliceArcInnerForStatic> = NonNull::from(&STATIC_INNER_SLICE);
+            let inner: NonNull<ArcInner<[T; 0]>> = inner.cast();
+            // `this` semantically is the Arc "owned" by the static, so make sure not to drop it.
+            let this: mem::ManuallyDrop<Arc<[T; 0]>> =
+                unsafe { mem::ManuallyDrop::new(Arc::from_inner(inner)) };
+            return (*this).clone();
+        }
+
+        // If T's alignment is too large for the static, make a new unique allocation.
+        let arr: [T; 0] = [];
+        Arc::from(arr)
+    }
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<T: ?Sized + Hash, A: Allocator> Hash for Arc<T, A> {
     fn hash<H: Hasher>(&self, state: &mut H) {
@@ -3506,7 +3675,7 @@
 
     fn try_from(boxed_slice: Arc<[T], A>) -> Result<Self, Self::Error> {
         if boxed_slice.len() == N {
-            let (ptr, alloc) = boxed_slice.internal_into_inner_with_allocator();
+            let (ptr, alloc) = Arc::into_inner_with_allocator(boxed_slice);
             Ok(unsafe { Arc::from_inner_in(ptr.cast(), alloc) })
         } else {
             Err(boxed_slice)
diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs
index 88aa1b1..22541a2 100644
--- a/library/alloc/src/vec/in_place_collect.rs
+++ b/library/alloc/src/vec/in_place_collect.rs
@@ -259,7 +259,8 @@
             inner.cap,
             inner.buf.cast::<T>(),
             inner.end as *const T,
-            inner.cap * mem::size_of::<I::Src>() / mem::size_of::<T>(),
+            // SAFETY: the multiplication can not overflow, since `inner.cap * size_of::<I::SRC>()` is the size of the allocation.
+            inner.cap.unchecked_mul(mem::size_of::<I::Src>()) / mem::size_of::<T>(),
         )
     };
 
@@ -374,7 +375,7 @@
         // - it lets us thread the write pointer through its innards and get it back in the end
         let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf };
         let sink =
-            self.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(end)).unwrap();
+            self.try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(end)).into_ok();
         // iteration succeeded, don't drop head
         unsafe { ManuallyDrop::new(sink).dst.sub_ptr(dst_buf) }
     }
diff --git a/library/alloc/src/vec/into_iter.rs b/library/alloc/src/vec/into_iter.rs
index b0226c8..c479893 100644
--- a/library/alloc/src/vec/into_iter.rs
+++ b/library/alloc/src/vec/into_iter.rs
@@ -289,6 +289,60 @@
         };
     }
 
+    fn fold<B, F>(mut self, mut accum: B, mut f: F) -> B
+    where
+        F: FnMut(B, Self::Item) -> B,
+    {
+        if T::IS_ZST {
+            while self.ptr.as_ptr() != self.end.cast_mut() {
+                // SAFETY: we just checked that `self.ptr` is in bounds.
+                let tmp = unsafe { self.ptr.read() };
+                // See `next` for why we subtract from `end` here.
+                self.end = self.end.wrapping_byte_sub(1);
+                accum = f(accum, tmp);
+            }
+        } else {
+            // SAFETY: `self.end` can only be null if `T` is a ZST.
+            while self.ptr != non_null!(self.end, T) {
+                // SAFETY: we just checked that `self.ptr` is in bounds.
+                let tmp = unsafe { self.ptr.read() };
+                // SAFETY: the maximum this can be is `self.end`.
+                // Increment `self.ptr` first to avoid double dropping in the event of a panic.
+                self.ptr = unsafe { self.ptr.add(1) };
+                accum = f(accum, tmp);
+            }
+        }
+        accum
+    }
+
+    fn try_fold<B, F, R>(&mut self, mut accum: B, mut f: F) -> R
+    where
+        Self: Sized,
+        F: FnMut(B, Self::Item) -> R,
+        R: core::ops::Try<Output = B>,
+    {
+        if T::IS_ZST {
+            while self.ptr.as_ptr() != self.end.cast_mut() {
+                // SAFETY: we just checked that `self.ptr` is in bounds.
+                let tmp = unsafe { self.ptr.read() };
+                // See `next` for why we subtract from `end` here.
+                self.end = self.end.wrapping_byte_sub(1);
+                accum = f(accum, tmp)?;
+            }
+        } else {
+            // SAFETY: `self.end` can only be null if `T` is a ZST.
+            while self.ptr != non_null!(self.end, T) {
+                // SAFETY: we just checked that `self.ptr` is in bounds.
+                let tmp = unsafe { self.ptr.read() };
+                // SAFETY: the maximum this can be is `self.end`.
+                // Increment `self.ptr` first to avoid double dropping in the event of a panic.
+                self.ptr = unsafe { self.ptr.add(1) };
+                accum = f(accum, tmp)?;
+            }
+        }
+        R::from_output(accum)
+    }
+
     unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item
     where
         Self: TrustedRandomAccessNoCoerce,
diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs
index df8a260..0078f5e 100644
--- a/library/alloc/tests/str.rs
+++ b/library/alloc/tests/str.rs
@@ -1848,6 +1848,9 @@
     assert_eq!("ΑΣ'Α".to_lowercase(), "ασ'α");
     assert_eq!("ΑΣ''Α".to_lowercase(), "ασ''α");
 
+    // https://github.com/rust-lang/rust/issues/124714
+    assert_eq!("abcdefghijklmnopΣ".to_lowercase(), "abcdefghijklmnopς");
+
     // a really long string that has it's lowercase form
     // even longer. this tests that implementations don't assume
     // an incorrect upper bound on allocations
diff --git a/library/core/Cargo.toml b/library/core/Cargo.toml
index a02fcf5..11d3397 100644
--- a/library/core/Cargo.toml
+++ b/library/core/Cargo.toml
@@ -31,6 +31,8 @@
 [features]
 # Make panics and failed asserts immediately abort without formatting any message
 panic_immediate_abort = []
+# Choose algorithms that are optimized for binary size instead of runtime performance
+optimize_for_size = []
 # Make `RefCell` store additional debugging information, which is printed out when
 # a borrow error occurs
 debug_refcell = []
diff --git a/library/core/benches/str.rs b/library/core/benches/str.rs
index 7d36eff..0f14809 100644
--- a/library/core/benches/str.rs
+++ b/library/core/benches/str.rs
@@ -3,6 +3,7 @@
 
 mod char_count;
 mod corpora;
+mod debug;
 mod iter;
 
 #[bench]
diff --git a/library/core/benches/str/debug.rs b/library/core/benches/str/debug.rs
new file mode 100644
index 0000000..7c72228
--- /dev/null
+++ b/library/core/benches/str/debug.rs
@@ -0,0 +1,79 @@
+//! This primarily benchmarks `impl Debug for str`,
+//! and it also explicitly tests that we minimizes calls to the underlying `Write`r.
+//! While that is an implementation detail and there are no guarantees about it,
+//! we should still try to minimize those calls over time rather than regress them.
+
+use std::fmt::{self, Write};
+use test::{black_box, Bencher};
+
+#[derive(Default)]
+struct CountingWriter {
+    buf: String,
+    write_calls: usize,
+}
+
+impl Write for CountingWriter {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        self.buf.push_str(s);
+        self.write_calls += 1;
+        Ok(())
+    }
+}
+
+fn assert_fmt(s: &str, expected: &str, expected_write_calls: usize) {
+    let mut w = CountingWriter::default();
+
+    write!(&mut w, "{s:?}").unwrap();
+    assert_eq!(s.len(), 64);
+    assert_eq!(w.buf, expected);
+    assert_eq!(w.write_calls, expected_write_calls);
+}
+
+#[bench]
+fn ascii_only(b: &mut Bencher) {
+    let s = "just a bit of ascii text that has no escapes. 64 bytes exactly!!";
+    assert_fmt(s, r#""just a bit of ascii text that has no escapes. 64 bytes exactly!!""#, 3);
+    b.iter(|| {
+        black_box(format!("{:?}", black_box(s)));
+    });
+}
+
+#[bench]
+fn ascii_escapes(b: &mut Bencher) {
+    let s = "some\tmore\tascii\ttext\nthis time with some \"escapes\", also 64 byte";
+    assert_fmt(
+        s,
+        r#""some\tmore\tascii\ttext\nthis time with some \"escapes\", also 64 byte""#,
+        21,
+    );
+    b.iter(|| {
+        black_box(format!("{:?}", black_box(s)));
+    });
+}
+
+#[bench]
+fn some_unicode(b: &mut Bencher) {
+    let s = "egy kis szöveg néhány unicode betűvel. legyen ez is 64 byte.";
+    assert_fmt(s, r#""egy kis szöveg néhány unicode betűvel. legyen ez is 64 byte.""#, 3);
+    b.iter(|| {
+        black_box(format!("{:?}", black_box(s)));
+    });
+}
+
+#[bench]
+fn mostly_unicode(b: &mut Bencher) {
+    let s = "предложение из кириллических букв.";
+    assert_fmt(s, r#""предложение из кириллических букв.""#, 3);
+    b.iter(|| {
+        black_box(format!("{:?}", black_box(s)));
+    });
+}
+
+#[bench]
+fn mixed(b: &mut Bencher) {
+    let s = "\"❤️\"\n\"hűha ez betű\"\n\"кириллических букв\".";
+    assert_fmt(s, r#""\"❤\u{fe0f}\"\n\"hűha ez betű\"\n\"кириллических букв\".""#, 36);
+    b.iter(|| {
+        black_box(format!("{:?}", black_box(s)));
+    });
+}
diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs
index e3d2cd2..b314d05 100644
--- a/library/core/src/array/iter.rs
+++ b/library/core/src/array/iter.rs
@@ -38,7 +38,7 @@
     alive: IndexRange,
 }
 
-// Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator`
+// Note: the `#[rustc_skip_during_method_dispatch(array)]` on `trait IntoIterator`
 // hides this implementation from explicit `.into_iter()` calls on editions < 2021,
 // so those calls will still resolve to the slice implementation, by reference.
 #[stable(feature = "array_into_iter_impl", since = "1.53.0")]
diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs
index c29e556..e9f4d0f 100644
--- a/library/core/src/ascii.rs
+++ b/library/core/src/ascii.rs
@@ -91,17 +91,21 @@
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn escape_default(c: u8) -> EscapeDefault {
-    let mut data = [Char::Null; 4];
-    let range = escape::escape_ascii_into(&mut data, c);
-    EscapeDefault(escape::EscapeIterInner::new(data, range))
+    EscapeDefault::new(c)
 }
 
 impl EscapeDefault {
-    pub(crate) fn empty() -> Self {
-        let data = [Char::Null; 4];
-        EscapeDefault(escape::EscapeIterInner::new(data, 0..0))
+    #[inline]
+    pub(crate) const fn new(c: u8) -> Self {
+        Self(escape::EscapeIterInner::ascii(c))
     }
 
+    #[inline]
+    pub(crate) fn empty() -> Self {
+        Self(escape::EscapeIterInner::empty())
+    }
+
+    #[inline]
     pub(crate) fn as_str(&self) -> &str {
         self.0.as_str()
     }
diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs
index a93b948..458be49 100644
--- a/library/core/src/char/methods.rs
+++ b/library/core/src/char/methods.rs
@@ -449,10 +449,10 @@
             '\"' if args.escape_double_quote => EscapeDebug::backslash(ascii::Char::QuotationMark),
             '\'' if args.escape_single_quote => EscapeDebug::backslash(ascii::Char::Apostrophe),
             _ if args.escape_grapheme_extended && self.is_grapheme_extended() => {
-                EscapeDebug::from_unicode(self.escape_unicode())
+                EscapeDebug::unicode(self)
             }
             _ if is_printable(self) => EscapeDebug::printable(self),
-            _ => EscapeDebug::from_unicode(self.escape_unicode()),
+            _ => EscapeDebug::unicode(self),
         }
     }
 
@@ -555,9 +555,9 @@
             '\t' => EscapeDefault::backslash(ascii::Char::SmallT),
             '\r' => EscapeDefault::backslash(ascii::Char::SmallR),
             '\n' => EscapeDefault::backslash(ascii::Char::SmallN),
-            '\\' | '\'' | '"' => EscapeDefault::backslash(self.as_ascii().unwrap()),
+            '\\' | '\'' | '\"' => EscapeDefault::backslash(self.as_ascii().unwrap()),
             '\x20'..='\x7e' => EscapeDefault::printable(self.as_ascii().unwrap()),
-            _ => EscapeDefault::from_unicode(self.escape_unicode()),
+            _ => EscapeDefault::unicode(self),
         }
     }
 
diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs
index a860c7c..f3683fe 100644
--- a/library/core/src/char/mod.rs
+++ b/library/core/src/char/mod.rs
@@ -152,10 +152,9 @@
 pub struct EscapeUnicode(escape::EscapeIterInner<10>);
 
 impl EscapeUnicode {
-    fn new(chr: char) -> Self {
-        let mut data = [ascii::Char::Null; 10];
-        let range = escape::escape_unicode_into(&mut data, chr);
-        Self(escape::EscapeIterInner::new(data, range))
+    #[inline]
+    const fn new(c: char) -> Self {
+        Self(escape::EscapeIterInner::unicode(c))
     }
 }
 
@@ -219,18 +218,19 @@
 pub struct EscapeDefault(escape::EscapeIterInner<10>);
 
 impl EscapeDefault {
-    fn printable(chr: ascii::Char) -> Self {
-        let data = [chr];
-        Self(escape::EscapeIterInner::from_array(data))
+    #[inline]
+    const fn printable(c: ascii::Char) -> Self {
+        Self(escape::EscapeIterInner::ascii(c.to_u8()))
     }
 
-    fn backslash(chr: ascii::Char) -> Self {
-        let data = [ascii::Char::ReverseSolidus, chr];
-        Self(escape::EscapeIterInner::from_array(data))
+    #[inline]
+    const fn backslash(c: ascii::Char) -> Self {
+        Self(escape::EscapeIterInner::backslash(c))
     }
 
-    fn from_unicode(esc: EscapeUnicode) -> Self {
-        Self(esc.0)
+    #[inline]
+    const fn unicode(c: char) -> Self {
+        Self(escape::EscapeIterInner::unicode(c))
     }
 }
 
@@ -304,23 +304,24 @@
 }
 
 impl EscapeDebug {
-    fn printable(chr: char) -> Self {
+    #[inline]
+    const fn printable(chr: char) -> Self {
         Self(EscapeDebugInner::Char(chr))
     }
 
-    fn backslash(chr: ascii::Char) -> Self {
-        let data = [ascii::Char::ReverseSolidus, chr];
-        let iter = escape::EscapeIterInner::from_array(data);
-        Self(EscapeDebugInner::Bytes(iter))
+    #[inline]
+    const fn backslash(c: ascii::Char) -> Self {
+        Self(EscapeDebugInner::Bytes(escape::EscapeIterInner::backslash(c)))
     }
 
-    fn from_unicode(esc: EscapeUnicode) -> Self {
-        Self(EscapeDebugInner::Bytes(esc.0))
+    #[inline]
+    const fn unicode(c: char) -> Self {
+        Self(EscapeDebugInner::Bytes(escape::EscapeIterInner::unicode(c)))
     }
 
+    #[inline]
     fn clear(&mut self) {
-        let bytes = escape::EscapeIterInner::from_array([]);
-        self.0 = EscapeDebugInner::Bytes(bytes);
+        self.0 = EscapeDebugInner::Bytes(escape::EscapeIterInner::empty());
     }
 }
 
@@ -339,6 +340,7 @@
         }
     }
 
+    #[inline]
     fn size_hint(&self) -> (usize, Option<usize>) {
         let n = self.len();
         (n, Some(n))
diff --git a/library/core/src/convert/num.rs b/library/core/src/convert/num.rs
index 935ead2..86c4ea9 100644
--- a/library/core/src/convert/num.rs
+++ b/library/core/src/convert/num.rs
@@ -165,8 +165,9 @@
 impl_from!(u32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
 
 // float -> float
-// FIXME(f16_f128): adding additional `From` impls for existing types breaks inference. See
-// <https://github.com/rust-lang/rust/issues/123824>
+// FIXME(f16_f128): adding additional `From<{float}>` impls to `f32` breaks inference. See
+// <https://github.com/rust-lang/rust/issues/123831>
+impl_from!(f16 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
 impl_from!(f16 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
 impl_from!(f32 => f64, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
 impl_from!(f32 => f128, #[stable(feature = "lossless_float_conv", since = "1.6.0")]);
diff --git a/library/core/src/escape.rs b/library/core/src/escape.rs
index 143e277..f6ec30b 100644
--- a/library/core/src/escape.rs
+++ b/library/core/src/escape.rs
@@ -6,56 +6,79 @@
 
 const HEX_DIGITS: [ascii::Char; 16] = *b"0123456789abcdef".as_ascii().unwrap();
 
-/// Escapes a byte into provided buffer; returns length of escaped
-/// representation.
-pub(crate) fn escape_ascii_into(output: &mut [ascii::Char; 4], byte: u8) -> Range<u8> {
-    #[inline]
-    fn backslash(a: ascii::Char) -> ([ascii::Char; 4], u8) {
-        ([ascii::Char::ReverseSolidus, a, ascii::Char::Null, ascii::Char::Null], 2)
-    }
+#[inline]
+const fn backslash<const N: usize>(a: ascii::Char) -> ([ascii::Char; N], Range<u8>) {
+    const { assert!(N >= 2) };
 
-    let (data, len) = match byte {
+    let mut output = [ascii::Char::Null; N];
+
+    output[0] = ascii::Char::ReverseSolidus;
+    output[1] = a;
+
+    (output, 0..2)
+}
+
+/// Escapes an ASCII character.
+///
+/// Returns a buffer and the length of the escaped representation.
+const fn escape_ascii<const N: usize>(byte: u8) -> ([ascii::Char; N], Range<u8>) {
+    const { assert!(N >= 4) };
+
+    match byte {
         b'\t' => backslash(ascii::Char::SmallT),
         b'\r' => backslash(ascii::Char::SmallR),
         b'\n' => backslash(ascii::Char::SmallN),
         b'\\' => backslash(ascii::Char::ReverseSolidus),
         b'\'' => backslash(ascii::Char::Apostrophe),
         b'\"' => backslash(ascii::Char::QuotationMark),
-        _ => {
-            if let Some(a) = byte.as_ascii()
+        byte => {
+            let mut output = [ascii::Char::Null; N];
+
+            if let Some(c) = byte.as_ascii()
                 && !byte.is_ascii_control()
             {
-                ([a, ascii::Char::Null, ascii::Char::Null, ascii::Char::Null], 1)
+                output[0] = c;
+                (output, 0..1)
             } else {
-                let hi = HEX_DIGITS[usize::from(byte >> 4)];
-                let lo = HEX_DIGITS[usize::from(byte & 0xf)];
-                ([ascii::Char::ReverseSolidus, ascii::Char::SmallX, hi, lo], 4)
+                let hi = HEX_DIGITS[(byte >> 4) as usize];
+                let lo = HEX_DIGITS[(byte & 0xf) as usize];
+
+                output[0] = ascii::Char::ReverseSolidus;
+                output[1] = ascii::Char::SmallX;
+                output[2] = hi;
+                output[3] = lo;
+
+                (output, 0..4)
             }
         }
-    };
-    *output = data;
-    0..len
+    }
 }
 
-/// Escapes a character into provided buffer using `\u{NNNN}` representation.
-pub(crate) fn escape_unicode_into(output: &mut [ascii::Char; 10], ch: char) -> Range<u8> {
+/// Escapes a character `\u{NNNN}` representation.
+///
+/// Returns a buffer and the length of the escaped representation.
+const fn escape_unicode<const N: usize>(c: char) -> ([ascii::Char; N], Range<u8>) {
+    const { assert!(N >= 10 && N < u8::MAX as usize) };
+
+    let c = u32::from(c);
+
+    // OR-ing `1` ensures that for `c == 0` the code computes that
+    // one digit should be printed.
+    let start = (c | 1).leading_zeros() as usize / 4 - 2;
+
+    let mut output = [ascii::Char::Null; N];
+    output[3] = HEX_DIGITS[((c >> 20) & 15) as usize];
+    output[4] = HEX_DIGITS[((c >> 16) & 15) as usize];
+    output[5] = HEX_DIGITS[((c >> 12) & 15) as usize];
+    output[6] = HEX_DIGITS[((c >> 8) & 15) as usize];
+    output[7] = HEX_DIGITS[((c >> 4) & 15) as usize];
+    output[8] = HEX_DIGITS[((c >> 0) & 15) as usize];
     output[9] = ascii::Char::RightCurlyBracket;
+    output[start + 0] = ascii::Char::ReverseSolidus;
+    output[start + 1] = ascii::Char::SmallU;
+    output[start + 2] = ascii::Char::LeftCurlyBracket;
 
-    let ch = ch as u32;
-    output[3] = HEX_DIGITS[((ch >> 20) & 15) as usize];
-    output[4] = HEX_DIGITS[((ch >> 16) & 15) as usize];
-    output[5] = HEX_DIGITS[((ch >> 12) & 15) as usize];
-    output[6] = HEX_DIGITS[((ch >> 8) & 15) as usize];
-    output[7] = HEX_DIGITS[((ch >> 4) & 15) as usize];
-    output[8] = HEX_DIGITS[((ch >> 0) & 15) as usize];
-
-    // or-ing 1 ensures that for ch==0 the code computes that one digit should
-    // be printed.
-    let start = (ch | 1).leading_zeros() as usize / 4 - 2;
-    const UNICODE_ESCAPE_PREFIX: &[ascii::Char; 3] = b"\\u{".as_ascii().unwrap();
-    output[start..][..3].copy_from_slice(UNICODE_ESCAPE_PREFIX);
-
-    (start as u8)..10
+    (output, (start as u8)..(N as u8))
 }
 
 /// An iterator over an fixed-size array.
@@ -65,45 +88,63 @@
 #[derive(Clone, Debug)]
 pub(crate) struct EscapeIterInner<const N: usize> {
     // The element type ensures this is always ASCII, and thus also valid UTF-8.
-    pub(crate) data: [ascii::Char; N],
+    data: [ascii::Char; N],
 
-    // Invariant: alive.start <= alive.end <= N.
-    pub(crate) alive: Range<u8>,
+    // Invariant: `alive.start <= alive.end <= N`
+    alive: Range<u8>,
 }
 
 impl<const N: usize> EscapeIterInner<N> {
-    pub fn new(data: [ascii::Char; N], alive: Range<u8>) -> Self {
-        const { assert!(N < 256) };
-        debug_assert!(alive.start <= alive.end && usize::from(alive.end) <= N, "{alive:?}");
-        Self { data, alive }
+    pub const fn backslash(c: ascii::Char) -> Self {
+        let (data, range) = backslash(c);
+        Self { data, alive: range }
     }
 
-    pub fn from_array<const M: usize>(array: [ascii::Char; M]) -> Self {
-        const { assert!(M <= N) };
-
-        let mut data = [ascii::Char::Null; N];
-        data[..M].copy_from_slice(&array);
-        Self::new(data, 0..M as u8)
+    pub const fn ascii(c: u8) -> Self {
+        let (data, range) = escape_ascii(c);
+        Self { data, alive: range }
     }
 
+    pub const fn unicode(c: char) -> Self {
+        let (data, range) = escape_unicode(c);
+        Self { data, alive: range }
+    }
+
+    #[inline]
+    pub const fn empty() -> Self {
+        Self { data: [ascii::Char::Null; N], alive: 0..0 }
+    }
+
+    #[inline]
     pub fn as_ascii(&self) -> &[ascii::Char] {
-        &self.data[usize::from(self.alive.start)..usize::from(self.alive.end)]
+        // SAFETY: `self.alive` is guaranteed to be a valid range for indexing `self.data`.
+        unsafe {
+            self.data.get_unchecked(usize::from(self.alive.start)..usize::from(self.alive.end))
+        }
     }
 
+    #[inline]
     pub fn as_str(&self) -> &str {
         self.as_ascii().as_str()
     }
 
+    #[inline]
     pub fn len(&self) -> usize {
         usize::from(self.alive.end - self.alive.start)
     }
 
     pub fn next(&mut self) -> Option<u8> {
-        self.alive.next().map(|i| self.data[usize::from(i)].to_u8())
+        let i = self.alive.next()?;
+
+        // SAFETY: `i` is guaranteed to be a valid index for `self.data`.
+        unsafe { Some(self.data.get_unchecked(usize::from(i)).to_u8()) }
     }
 
     pub fn next_back(&mut self) -> Option<u8> {
-        self.alive.next_back().map(|i| self.data[usize::from(i)].to_u8())
+        let i = self.alive.next_back()?;
+
+        // SAFETY: `i` is guaranteed to be a valid index for `self.data`.
+        unsafe { Some(self.data.get_unchecked(usize::from(i)).to_u8()) }
     }
 
     pub fn advance_by(&mut self, n: usize) -> Result<(), NonZero<usize>> {
diff --git a/library/core/src/fmt/fmt_trait_method_doc.md b/library/core/src/fmt/fmt_trait_method_doc.md
new file mode 100644
index 0000000..493d929
--- /dev/null
+++ b/library/core/src/fmt/fmt_trait_method_doc.md
@@ -0,0 +1,8 @@
+Formats the value using the given formatter.
+
+# Errors
+
+This function should return [`Err`] if, and only if, the provided [`Formatter`] returns [`Err`].
+String formatting is considered an infallible operation; this function only
+returns a [`Result`] because writing to the underlying stream might fail and it must
+provide a way to propagate the fact that an error has occurred back up the stack.
diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs
index ce0643a..9b372ea 100644
--- a/library/core/src/fmt/mod.rs
+++ b/library/core/src/fmt/mod.rs
@@ -72,14 +72,24 @@
 /// The error type which is returned from formatting a message into a stream.
 ///
 /// This type does not support transmission of an error other than that an error
-/// occurred. Any extra information must be arranged to be transmitted through
-/// some other means.
+/// occurred. This is because, despite the existence of this error,
+/// string formatting is considered an infallible operation.
+/// `fmt()` implementors should not return this `Error` unless they received it from their
+/// [`Formatter`]. The only time your code should create a new instance of this
+/// error is when implementing `fmt::Write`, in order to cancel the formatting operation when
+/// writing to the underlying stream fails.
 ///
-/// An important thing to remember is that the type `fmt::Error` should not be
+/// Any extra information must be arranged to be transmitted through some other means,
+/// such as storing it in a field to be consulted after the formatting operation has been
+/// cancelled. (For example, this is how [`std::io::Write::write_fmt()`] propagates IO errors
+/// during writing.)
+///
+/// This type, `fmt::Error`, should not be
 /// confused with [`std::io::Error`] or [`std::error::Error`], which you may also
 /// have in scope.
 ///
 /// [`std::io::Error`]: ../../std/io/struct.Error.html
+/// [`std::io::Write::write_fmt()`]: ../../std/io/trait.Write.html#method.write_fmt
 /// [`std::error::Error`]: ../../std/error/trait.Error.html
 ///
 /// # Examples
@@ -118,8 +128,10 @@
     /// This function will return an instance of [`std::fmt::Error`][Error] on error.
     ///
     /// The purpose of that error is to abort the formatting operation when the underlying
-    /// destination encounters some error preventing it from accepting more text; it should
-    /// generally be propagated rather than handled, at least when implementing formatting traits.
+    /// destination encounters some error preventing it from accepting more text;
+    /// in particular, it does not communicate any information about *what* error occurred.
+    /// It should generally be propagated rather than handled, at least when implementing
+    /// formatting traits.
     ///
     /// # Examples
     ///
@@ -586,7 +598,7 @@
 #[rustc_diagnostic_item = "Debug"]
 #[rustc_trivial_field_reads]
 pub trait Debug {
-    /// Formats the value using the given formatter.
+    #[doc = include_str!("fmt_trait_method_doc.md")]
     ///
     /// # Examples
     ///
@@ -703,7 +715,7 @@
 #[rustc_diagnostic_item = "Display"]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Display {
-    /// Formats the value using the given formatter.
+    #[doc = include_str!("fmt_trait_method_doc.md")]
     ///
     /// # Examples
     ///
@@ -777,7 +789,7 @@
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Octal {
-    /// Formats the value using the given formatter.
+    #[doc = include_str!("fmt_trait_method_doc.md")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
 }
@@ -836,7 +848,7 @@
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Binary {
-    /// Formats the value using the given formatter.
+    #[doc = include_str!("fmt_trait_method_doc.md")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
 }
@@ -891,7 +903,7 @@
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait LowerHex {
-    /// Formats the value using the given formatter.
+    #[doc = include_str!("fmt_trait_method_doc.md")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
 }
@@ -946,7 +958,7 @@
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait UpperHex {
-    /// Formats the value using the given formatter.
+    #[doc = include_str!("fmt_trait_method_doc.md")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
 }
@@ -997,7 +1009,7 @@
 #[stable(feature = "rust1", since = "1.0.0")]
 #[rustc_diagnostic_item = "Pointer"]
 pub trait Pointer {
-    /// Formats the value using the given formatter.
+    #[doc = include_str!("fmt_trait_method_doc.md")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
 }
@@ -1048,7 +1060,7 @@
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait LowerExp {
-    /// Formats the value using the given formatter.
+    #[doc = include_str!("fmt_trait_method_doc.md")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
 }
@@ -1099,7 +1111,7 @@
 /// ```
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait UpperExp {
-    /// Formats the value using the given formatter.
+    #[doc = include_str!("fmt_trait_method_doc.md")]
     #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, f: &mut Formatter<'_>) -> Result;
 }
diff --git a/library/core/src/fmt/nofloat.rs b/library/core/src/fmt/nofloat.rs
index a36e7ef..6b07236 100644
--- a/library/core/src/fmt/nofloat.rs
+++ b/library/core/src/fmt/nofloat.rs
@@ -4,6 +4,7 @@
     ($ty:ident) => {
         #[stable(feature = "rust1", since = "1.0.0")]
         impl Debug for $ty {
+            #[inline]
             fn fmt(&self, _fmt: &mut Formatter<'_>) -> Result {
                 panic!("floating point support is turned off");
             }
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 1027d48..5a2a4c5 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1483,10 +1483,10 @@
     ///
     /// # Safety
     ///
-    /// Both the starting and resulting pointer must be either in bounds or one
-    /// byte past the end of an allocated object. If either pointer is out of
-    /// bounds or arithmetic overflow occurs then any further use of the
-    /// returned value will result in undefined behavior.
+    /// If the computed offset is non-zero, then both the starting and resulting pointer must be
+    /// either in bounds or at the end of an allocated object. If either pointer is out
+    /// of bounds or arithmetic overflow occurs then any further use of the returned value will
+    /// result in undefined behavior.
     ///
     /// The stabilized version of this intrinsic is [`pointer::offset`].
     #[must_use = "returns a new pointer rather than modifying its argument"]
@@ -1502,7 +1502,7 @@
     /// # Safety
     ///
     /// Unlike the `offset` intrinsic, this intrinsic does not restrict the
-    /// resulting pointer to point into or one byte past the end of an allocated
+    /// resulting pointer to point into or at the end of an allocated
     /// object, and it wraps with two's complement arithmetic. The resulting
     /// value is not necessarily valid to be used to actually access memory.
     ///
@@ -1594,6 +1594,12 @@
     #[rustc_nounwind]
     pub fn sqrtf64(x: f64) -> f64;
 
+    /// Raises an `f16` to an integer power.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f16::powi`](../../std/primitive.f16.html#method.powi)
+    #[rustc_nounwind]
+    pub fn powif16(a: f16, x: i32) -> f16;
     /// Raises an `f32` to an integer power.
     ///
     /// The stabilized version of this intrinsic is
@@ -1606,6 +1612,12 @@
     /// [`f64::powi`](../../std/primitive.f64.html#method.powi)
     #[rustc_nounwind]
     pub fn powif64(a: f64, x: i32) -> f64;
+    /// Raises an `f128` to an integer power.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f128::powi`](../../std/primitive.f128.html#method.powi)
+    #[rustc_nounwind]
+    pub fn powif128(a: f128, x: i32) -> f128;
 
     /// Returns the sine of an `f32`.
     ///
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index ceea679..d1be534 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -569,6 +569,13 @@
     #[rustc_nounwind]
     pub fn simd_ctlz<T>(x: T) -> T;
 
+    /// Count the number of ones in each element.
+    ///
+    /// `T` must be a vector of integers.
+    #[rustc_nounwind]
+    #[cfg(not(bootstrap))]
+    pub fn simd_ctpop<T>(x: T) -> T;
+
     /// Count the trailing zeros of each element.
     ///
     /// `T` must be a vector of integers.
diff --git a/library/core/src/io/borrowed_buf.rs b/library/core/src/io/borrowed_buf.rs
index 8137170..d497da3 100644
--- a/library/core/src/io/borrowed_buf.rs
+++ b/library/core/src/io/borrowed_buf.rs
@@ -92,14 +92,20 @@
     #[inline]
     pub fn filled(&self) -> &[u8] {
         // SAFETY: We only slice the filled part of the buffer, which is always valid
-        unsafe { MaybeUninit::slice_assume_init_ref(&self.buf[0..self.filled]) }
+        unsafe {
+            let buf = self.buf.get_unchecked(..self.filled);
+            MaybeUninit::slice_assume_init_ref(buf)
+        }
     }
 
     /// Returns a mutable reference to the filled portion of the buffer.
     #[inline]
     pub fn filled_mut(&mut self) -> &mut [u8] {
         // SAFETY: We only slice the filled part of the buffer, which is always valid
-        unsafe { MaybeUninit::slice_assume_init_mut(&mut self.buf[0..self.filled]) }
+        unsafe {
+            let buf = self.buf.get_unchecked_mut(..self.filled);
+            MaybeUninit::slice_assume_init_mut(buf)
+        }
     }
 
     /// Returns a cursor over the unfilled part of the buffer.
@@ -205,7 +211,10 @@
     #[inline]
     pub fn init_ref(&self) -> &[u8] {
         // SAFETY: We only slice the initialized part of the buffer, which is always valid
-        unsafe { MaybeUninit::slice_assume_init_ref(&self.buf.buf[self.buf.filled..self.buf.init]) }
+        unsafe {
+            let buf = self.buf.buf.get_unchecked(self.buf.filled..self.buf.init);
+            MaybeUninit::slice_assume_init_ref(buf)
+        }
     }
 
     /// Returns a mutable reference to the initialized portion of the cursor.
@@ -213,7 +222,8 @@
     pub fn init_mut(&mut self) -> &mut [u8] {
         // SAFETY: We only slice the initialized part of the buffer, which is always valid
         unsafe {
-            MaybeUninit::slice_assume_init_mut(&mut self.buf.buf[self.buf.filled..self.buf.init])
+            let buf = self.buf.buf.get_unchecked_mut(self.buf.filled..self.buf.init);
+            MaybeUninit::slice_assume_init_mut(buf)
         }
     }
 
@@ -222,7 +232,8 @@
     /// It is safe to uninitialize any of these bytes.
     #[inline]
     pub fn uninit_mut(&mut self) -> &mut [MaybeUninit<u8>] {
-        &mut self.buf.buf[self.buf.init..]
+        // SAFETY: always in bounds
+        unsafe { self.buf.buf.get_unchecked_mut(self.buf.init..) }
     }
 
     /// Returns a mutable reference to the whole cursor.
@@ -232,7 +243,8 @@
     /// The caller must not uninitialize any bytes in the initialized portion of the cursor.
     #[inline]
     pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
-        &mut self.buf.buf[self.buf.filled..]
+        // SAFETY: always in bounds
+        unsafe { self.buf.buf.get_unchecked_mut(self.buf.filled..) }
     }
 
     /// Advance the cursor by asserting that `n` bytes have been filled.
diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs
index a5cf069..abdf2f4 100644
--- a/library/core/src/iter/adapters/step_by.rs
+++ b/library/core/src/iter/adapters/step_by.rs
@@ -1,7 +1,7 @@
 use crate::{
     intrinsics,
     iter::{from_fn, TrustedLen, TrustedRandomAccess},
-    num::NonZeroUsize,
+    num::NonZero,
     ops::{Range, Try},
 };
 
@@ -42,10 +42,10 @@
     /// The `step` that was originally passed to `Iterator::step_by(step)`,
     /// aka `self.step_minus_one + 1`.
     #[inline]
-    fn original_step(&self) -> NonZeroUsize {
+    fn original_step(&self) -> NonZero<usize> {
         // SAFETY: By type invariant, `step_minus_one` cannot be `MAX`, which
         // means the addition cannot overflow and the result cannot be zero.
-        unsafe { NonZeroUsize::new_unchecked(intrinsics::unchecked_add(self.step_minus_one, 1)) }
+        unsafe { NonZero::new_unchecked(intrinsics::unchecked_add(self.step_minus_one, 1)) }
     }
 }
 
@@ -231,12 +231,12 @@
     #[inline]
     default fn spec_size_hint(&self) -> (usize, Option<usize>) {
         #[inline]
-        fn first_size(step: NonZeroUsize) -> impl Fn(usize) -> usize {
+        fn first_size(step: NonZero<usize>) -> impl Fn(usize) -> usize {
             move |n| if n == 0 { 0 } else { 1 + (n - 1) / step }
         }
 
         #[inline]
-        fn other_size(step: NonZeroUsize) -> impl Fn(usize) -> usize {
+        fn other_size(step: NonZero<usize>) -> impl Fn(usize) -> usize {
             move |n| n / step
         }
 
diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs
index 5637812..d9d860c 100644
--- a/library/core/src/iter/traits/collect.rs
+++ b/library/core/src/iter/traits/collect.rs
@@ -268,7 +268,6 @@
 /// }
 /// ```
 #[rustc_diagnostic_item = "IntoIterator"]
-#[rustc_skip_array_during_method_dispatch]
 #[rustc_on_unimplemented(
     on(
         _Self = "core::ops::range::RangeTo<Idx>",
@@ -312,6 +311,8 @@
     label = "`{Self}` is not an iterator",
     message = "`{Self}` is not an iterator"
 )]
+#[cfg_attr(bootstrap, rustc_skip_array_during_method_dispatch)]
+#[cfg_attr(not(bootstrap), rustc_skip_during_method_dispatch(array, boxed_slice))]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait IntoIterator {
     /// The type of the elements being iterated over.
diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs
index 955efb9..e0c3b9f 100644
--- a/library/core/src/mem/manually_drop.rs
+++ b/library/core/src/mem/manually_drop.rs
@@ -1,7 +1,7 @@
 use crate::ops::{Deref, DerefMut, DerefPure};
 use crate::ptr;
 
-/// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
+/// A wrapper to inhibit the compiler from automatically calling `T`’s destructor.
 /// This wrapper is 0-cost.
 ///
 /// `ManuallyDrop<T>` is guaranteed to have the same layout and bit validity as
diff --git a/library/core/src/num/f128.rs b/library/core/src/num/f128.rs
index 8fe81a9..9362dc8 100644
--- a/library/core/src/num/f128.rs
+++ b/library/core/src/num/f128.rs
@@ -228,6 +228,16 @@
     /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
     /// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
     /// See [explanation of NaN as a special value](f32) for more info.
+    ///
+    /// ```
+    /// #![feature(f128)]
+    ///
+    /// let f = 7.0_f128;
+    /// let g = -7.0_f128;
+    ///
+    /// assert!(f.is_sign_positive());
+    /// assert!(!g.is_sign_positive());
+    /// ```
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
@@ -241,6 +251,16 @@
     /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
     /// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
     /// See [explanation of NaN as a special value](f32) for more info.
+    ///
+    /// ```
+    /// #![feature(f128)]
+    ///
+    /// let f = 7.0_f128;
+    /// let g = -7.0_f128;
+    ///
+    /// assert!(!f.is_sign_negative());
+    /// assert!(g.is_sign_negative());
+    /// ```
     #[inline]
     #[must_use]
     #[unstable(feature = "f128", issue = "116909")]
diff --git a/library/core/src/num/f16.rs b/library/core/src/num/f16.rs
index 4290245..c4d4584 100644
--- a/library/core/src/num/f16.rs
+++ b/library/core/src/num/f16.rs
@@ -224,6 +224,16 @@
     /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
     /// `is_sign_positive` on a NaN might produce an unexpected result in some cases.
     /// See [explanation of NaN as a special value](f32) for more info.
+    ///
+    /// ```
+    /// #![feature(f16)]
+    ///
+    /// let f = 7.0_f16;
+    /// let g = -7.0_f16;
+    ///
+    /// assert!(f.is_sign_positive());
+    /// assert!(!g.is_sign_positive());
+    /// ```
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
@@ -237,6 +247,16 @@
     /// the bit pattern of NaNs are conserved over arithmetic operations, the result of
     /// `is_sign_negative` on a NaN might produce an unexpected result in some cases.
     /// See [explanation of NaN as a special value](f32) for more info.
+    ///
+    /// ```
+    /// #![feature(f16)]
+    ///
+    /// let f = 7.0_f16;
+    /// let g = -7.0_f16;
+    ///
+    /// assert!(!f.is_sign_negative());
+    /// assert!(g.is_sign_negative());
+    /// ```
     #[inline]
     #[must_use]
     #[unstable(feature = "f16", issue = "116909")]
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index d56f346d..db8e1f3 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -1111,7 +1111,6 @@
     /// ```
     /// assert!((1f64).to_bits() != 1f64 as u64); // to_bits() is not casting!
     /// assert_eq!((12.5f64).to_bits(), 0x4029000000000000);
-    ///
     /// ```
     #[must_use = "this returns the result of the operation, \
                   without modifying the original"]
diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs
index c02f73f..09a341e 100644
--- a/library/core/src/num/mod.rs
+++ b/library/core/src/num/mod.rs
@@ -1412,11 +1412,9 @@
 #[cfg_attr(feature = "panic_immediate_abort", inline)]
 #[cold]
 #[track_caller]
-const fn from_str_radix_assert(radix: u32) {
-    if 2 > radix || radix > 36 {
-        // The only difference between these two functions is their panic message.
-        intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt);
-    }
+const fn from_str_radix_panic(radix: u32) {
+    // The only difference between these two functions is their panic message.
+    intrinsics::const_eval_select((radix,), from_str_radix_panic_ct, from_str_radix_panic_rt);
 }
 
 macro_rules! from_str_radix {
@@ -1450,7 +1448,9 @@
                 use self::IntErrorKind::*;
                 use self::ParseIntError as PIE;
 
-                from_str_radix_assert(radix);
+                if 2 > radix || radix > 36 {
+                    from_str_radix_panic(radix);
+                }
 
                 if src.is_empty() {
                     return Err(PIE { kind: Empty });
diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs
index 5d3ae73..fcdd983 100644
--- a/library/core/src/num/nonzero.rs
+++ b/library/core/src/num/nonzero.rs
@@ -453,8 +453,7 @@
         #[$stability:meta]
         Self = $Ty:ident,
         Primitive = $signedness:ident $Int:ident,
-        $(UnsignedNonZero = $UnsignedNonZero:ident,)?
-        UnsignedPrimitive = $UnsignedPrimitive:ty,
+        UnsignedPrimitive = $Uint:ty,
 
         // Used in doc comments.
         leading_zeros_test = $leading_zeros_test:expr,
@@ -492,7 +491,7 @@
         #[$stability]
         pub type $Ty = NonZero<$Int>;
 
-        impl $Ty {
+        impl NonZero<$Int> {
             /// The size of this non-zero integer type in bits.
             ///
             #[doc = concat!("This value is equal to [`", stringify!($Int), "::BITS`].")]
@@ -500,9 +499,9 @@
             /// # Examples
             ///
             /// ```
-            #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
-            ///
-            #[doc = concat!("assert_eq!(", stringify!($Ty), "::BITS, ", stringify!($Int), "::BITS);")]
+            /// # use std::num::NonZero;
+            /// #
+            #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::BITS, ", stringify!($Int), "::BITS);")]
             /// ```
             #[stable(feature = "nonzero_bits", since = "1.67.0")]
             pub const BITS: u32 = <$Int>::BITS;
@@ -516,7 +515,9 @@
             /// Basic usage:
             ///
             /// ```
-            #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(", $leading_zeros_test, ").unwrap();")]
+            /// # use std::num::NonZero;
+            /// #
+            #[doc = concat!("let n = NonZero::<", stringify!($Int), ">::new(", $leading_zeros_test, ").unwrap();")]
             ///
             /// assert_eq!(n.leading_zeros(), 0);
             /// ```
@@ -528,7 +529,7 @@
             pub const fn leading_zeros(self) -> u32 {
                 // SAFETY: since `self` cannot be zero, it is safe to call `ctlz_nonzero`.
                 unsafe {
-                    intrinsics::ctlz_nonzero(self.get() as $UnsignedPrimitive)
+                    intrinsics::ctlz_nonzero(self.get() as $Uint)
                 }
             }
 
@@ -542,7 +543,9 @@
             /// Basic usage:
             ///
             /// ```
-            #[doc = concat!("let n = std::num::", stringify!($Ty), "::new(0b0101000).unwrap();")]
+            /// # use std::num::NonZero;
+            /// #
+            #[doc = concat!("let n = NonZero::<", stringify!($Int), ">::new(0b0101000).unwrap();")]
             ///
             /// assert_eq!(n.trailing_zeros(), 3);
             /// ```
@@ -554,7 +557,7 @@
             pub const fn trailing_zeros(self) -> u32 {
                 // SAFETY: since `self` cannot be zero, it is safe to call `cttz_nonzero`.
                 unsafe {
-                    intrinsics::cttz_nonzero(self.get() as $UnsignedPrimitive)
+                    intrinsics::cttz_nonzero(self.get() as $Uint)
                 }
             }
 
@@ -567,10 +570,10 @@
             /// ```
             /// #![feature(non_zero_count_ones)]
             ///
+            /// # use std::num::NonZero;
+            /// #
             /// # fn main() { test().unwrap(); }
             /// # fn test() -> Option<()> {
-            /// # use std::num::*;
-            /// #
             #[doc = concat!("let a = NonZero::<", stringify!($Int), ">::new(0b100_0000)?;")]
             #[doc = concat!("let b = NonZero::<", stringify!($Int), ">::new(0b100_0011)?;")]
             ///
@@ -597,8 +600,7 @@
             nonzero_integer_signedness_dependent_methods! {
                 Self = $Ty,
                 Primitive = $signedness $Int,
-                $(UnsignedNonZero = $UnsignedNonZero,)?
-                UnsignedPrimitive = $UnsignedPrimitive,
+                UnsignedPrimitive = $Uint,
             }
 
             /// Multiplies two non-zero integers together.
@@ -608,13 +610,13 @@
             /// # Examples
             ///
             /// ```
-            #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+            /// # use std::num::NonZero;
+            /// #
             /// # fn main() { test().unwrap(); }
             /// # fn test() -> Option<()> {
-            #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
-            #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")]
-            #[doc = concat!("let max = ", stringify!($Ty), "::new(",
-                            stringify!($Int), "::MAX)?;")]
+            #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")]
+            #[doc = concat!("let four = NonZero::new(4", stringify!($Int), ")?;")]
+            #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")]
             ///
             /// assert_eq!(Some(four), two.checked_mul(two));
             /// assert_eq!(None, max.checked_mul(two));
@@ -642,18 +644,18 @@
             }
 
             /// Multiplies two non-zero integers together.
-            #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")]
+            #[doc = concat!("Return [`NonZero::<", stringify!($Int), ">::MAX`] on overflow.")]
             ///
             /// # Examples
             ///
             /// ```
-            #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+            /// # use std::num::NonZero;
+            /// #
             /// # fn main() { test().unwrap(); }
             /// # fn test() -> Option<()> {
-            #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
-            #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")]
-            #[doc = concat!("let max = ", stringify!($Ty), "::new(",
-                            stringify!($Int), "::MAX)?;")]
+            #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")]
+            #[doc = concat!("let four = NonZero::new(4", stringify!($Int), ")?;")]
+            #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")]
             ///
             /// assert_eq!(four, two.saturating_mul(two));
             /// assert_eq!(max, four.saturating_mul(max));
@@ -698,11 +700,12 @@
             /// ```
             /// #![feature(nonzero_ops)]
             ///
-            #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+            /// # use std::num::NonZero;
+            /// #
             /// # fn main() { test().unwrap(); }
             /// # fn test() -> Option<()> {
-            #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
-            #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")]
+            #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")]
+            #[doc = concat!("let four = NonZero::new(4", stringify!($Int), ")?;")]
             ///
             /// assert_eq!(four, unsafe { two.unchecked_mul(two) });
             /// # Some(())
@@ -724,13 +727,13 @@
             /// # Examples
             ///
             /// ```
-            #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+            /// # use std::num::NonZero;
+            /// #
             /// # fn main() { test().unwrap(); }
             /// # fn test() -> Option<()> {
-            #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")]
-            #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")]
-            #[doc = concat!("let half_max = ", stringify!($Ty), "::new(",
-                            stringify!($Int), "::MAX / 2)?;")]
+            #[doc = concat!("let three = NonZero::new(3", stringify!($Int), ")?;")]
+            #[doc = concat!("let twenty_seven = NonZero::new(27", stringify!($Int), ")?;")]
+            #[doc = concat!("let half_max = NonZero::new(", stringify!($Int), "::MAX / 2)?;")]
             ///
             /// assert_eq!(Some(twenty_seven), three.checked_pow(3));
             /// assert_eq!(None, half_max.checked_pow(3));
@@ -761,24 +764,24 @@
             #[doc = sign_dependent_expr!{
                 $signedness ?
                 if signed {
-                    concat!("Return [`", stringify!($Ty), "::MIN`] ",
-                                "or [`", stringify!($Ty), "::MAX`] on overflow.")
+                    concat!("Return [`NonZero::<", stringify!($Int), ">::MIN`] ",
+                                "or [`NonZero::<", stringify!($Int), ">::MAX`] on overflow.")
                 }
                 if unsigned {
-                    concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")
+                    concat!("Return [`NonZero::<", stringify!($Int), ">::MAX`] on overflow.")
                 }
             }]
             ///
             /// # Examples
             ///
             /// ```
-            #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+            /// # use std::num::NonZero;
+            /// #
             /// # fn main() { test().unwrap(); }
             /// # fn test() -> Option<()> {
-            #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")]
-            #[doc = concat!("let twenty_seven = ", stringify!($Ty), "::new(27)?;")]
-            #[doc = concat!("let max = ", stringify!($Ty), "::new(",
-                            stringify!($Int), "::MAX)?;")]
+            #[doc = concat!("let three = NonZero::new(3", stringify!($Int), ")?;")]
+            #[doc = concat!("let twenty_seven = NonZero::new(27", stringify!($Int), ")?;")]
+            #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")]
             ///
             /// assert_eq!(twenty_seven, three.saturating_pow(3));
             /// assert_eq!(max, max.saturating_pow(3));
@@ -804,7 +807,7 @@
         }
 
         #[stable(feature = "nonzero_parse", since = "1.35.0")]
-        impl FromStr for $Ty {
+        impl FromStr for NonZero<$Int> {
             type Err = ParseIntError;
             fn from_str(src: &str) -> Result<Self, Self::Err> {
                 Self::new(<$Int>::from_str_radix(src, 10)?)
@@ -842,56 +845,55 @@
     // Impls for unsigned nonzero types only.
     ($Ty:ident unsigned $Int:ty) => {
         #[stable(feature = "nonzero_div", since = "1.51.0")]
-        impl Div<$Ty> for $Int {
+        impl Div<NonZero<$Int>> for $Int {
             type Output = $Int;
 
-            /// This operation rounds towards zero,
-            /// truncating any fractional part of the exact result, and cannot panic.
+            /// This operation rounds towards zero, truncating any fractional
+            /// part of the exact result, and cannot panic.
             #[inline]
-            fn div(self, other: $Ty) -> $Int {
-                // SAFETY: div by zero is checked because `other` is a nonzero,
+            fn div(self, other: NonZero<$Int>) -> $Int {
+                // SAFETY: Division by zero is checked because `other` is non-zero,
                 // and MIN/-1 is checked because `self` is an unsigned int.
                 unsafe { intrinsics::unchecked_div(self, other.get()) }
             }
         }
 
         #[stable(feature = "nonzero_div_assign", since = "1.79.0")]
-        impl DivAssign<$Ty> for $Int {
-            /// This operation rounds towards zero,
-            /// truncating any fractional part of the exact result, and cannot panic.
+        impl DivAssign<NonZero<$Int>> for $Int {
+            /// This operation rounds towards zero, truncating any fractional
+            /// part of the exact result, and cannot panic.
             #[inline]
-            fn div_assign(&mut self, other: $Ty) {
+            fn div_assign(&mut self, other: NonZero<$Int>) {
                 *self = *self / other;
             }
         }
 
         #[stable(feature = "nonzero_div", since = "1.51.0")]
-        impl Rem<$Ty> for $Int {
+        impl Rem<NonZero<$Int>> for $Int {
             type Output = $Int;
 
             /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic.
             #[inline]
-            fn rem(self, other: $Ty) -> $Int {
-                // SAFETY: rem by zero is checked because `other` is a nonzero,
+            fn rem(self, other: NonZero<$Int>) -> $Int {
+                // SAFETY: Remainder by zero is checked because `other` is non-zero,
                 // and MIN/-1 is checked because `self` is an unsigned int.
                 unsafe { intrinsics::unchecked_rem(self, other.get()) }
             }
         }
 
         #[stable(feature = "nonzero_div_assign", since = "1.79.0")]
-        impl RemAssign<$Ty> for $Int {
+        impl RemAssign<NonZero<$Int>> for $Int {
             /// This operation satisfies `n % d == n - (n / d) * d`, and cannot panic.
             #[inline]
-            fn rem_assign(&mut self, other: $Ty) {
+            fn rem_assign(&mut self, other: NonZero<$Int>) {
                 *self = *self % other;
             }
         }
     };
-
     // Impls for signed nonzero types only.
     ($Ty:ident signed $Int:ty) => {
         #[stable(feature = "signed_nonzero_neg", since = "1.71.0")]
-        impl Neg for $Ty {
+        impl Neg for NonZero<$Int> {
             type Output = Self;
 
             #[inline]
@@ -901,7 +903,7 @@
             }
         }
 
-        forward_ref_unop! { impl Neg, neg for $Ty,
+        forward_ref_unop! { impl Neg, neg for NonZero<$Int>,
         #[stable(feature = "signed_nonzero_neg", since = "1.71.0")] }
     };
 }
@@ -920,8 +922,9 @@
         /// # Examples
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
-        #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), 1", stringify!($Int), ");")]
+        /// # use std::num::NonZero;
+        /// #
+        #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::MIN.get(), 1", stringify!($Int), ");")]
         /// ```
         #[stable(feature = "nonzero_min_max", since = "1.70.0")]
         pub const MIN: Self = Self::new(1).unwrap();
@@ -933,8 +936,9 @@
         /// # Examples
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
-        #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")]
+        /// # use std::num::NonZero;
+        /// #
+        #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::MAX.get(), ", stringify!($Int), "::MAX);")]
         /// ```
         #[stable(feature = "nonzero_min_max", since = "1.70.0")]
         pub const MAX: Self = Self::new(<$Int>::MAX).unwrap();
@@ -947,13 +951,13 @@
         /// # Examples
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")]
-        #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
-        #[doc = concat!("let max = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MAX)?;")]
+        #[doc = concat!("let one = NonZero::new(1", stringify!($Int), ")?;")]
+        #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")]
+        #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")]
         ///
         /// assert_eq!(Some(two), one.checked_add(1));
         /// assert_eq!(None, max.checked_add(1));
@@ -981,18 +985,18 @@
         }
 
         /// Adds an unsigned integer to a non-zero value.
-        #[doc = concat!("Return [`", stringify!($Ty), "::MAX`] on overflow.")]
+        #[doc = concat!("Return [`NonZero::<", stringify!($Int), ">::MAX`] on overflow.")]
         ///
         /// # Examples
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")]
-        #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
-        #[doc = concat!("let max = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MAX)?;")]
+        #[doc = concat!("let one = NonZero::new(1", stringify!($Int), ")?;")]
+        #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")]
+        #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")]
         ///
         /// assert_eq!(two, one.saturating_add(1));
         /// assert_eq!(max, max.saturating_add(1));
@@ -1027,11 +1031,12 @@
         /// ```
         /// #![feature(nonzero_ops)]
         ///
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")]
-        #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
+        #[doc = concat!("let one = NonZero::new(1", stringify!($Int), ")?;")]
+        #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")]
         ///
         /// assert_eq!(two, unsafe { one.unchecked_add(1) });
         /// # Some(())
@@ -1054,14 +1059,14 @@
         /// # Examples
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
-        #[doc = concat!("let three = ", stringify!($Ty), "::new(3)?;")]
-        #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")]
-        #[doc = concat!("let max = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MAX)?;")]
+        #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")]
+        #[doc = concat!("let three = NonZero::new(3", stringify!($Int), ")?;")]
+        #[doc = concat!("let four = NonZero::new(4", stringify!($Int), ")?;")]
+        #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")]
         ///
         /// assert_eq!(Some(two), two.checked_next_power_of_two() );
         /// assert_eq!(Some(four), three.checked_next_power_of_two() );
@@ -1094,10 +1099,11 @@
         /// # Examples
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
-        #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")]
-        #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")]
-        #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")]
+        /// # use std::num::NonZero;
+        /// #
+        #[doc = concat!("assert_eq!(NonZero::new(7", stringify!($Int), ").unwrap().ilog2(), 2);")]
+        #[doc = concat!("assert_eq!(NonZero::new(8", stringify!($Int), ").unwrap().ilog2(), 3);")]
+        #[doc = concat!("assert_eq!(NonZero::new(9", stringify!($Int), ").unwrap().ilog2(), 3);")]
         /// ```
         #[stable(feature = "int_log", since = "1.67.0")]
         #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
@@ -1118,10 +1124,11 @@
         /// # Examples
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
-        #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")]
-        #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")]
-        #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")]
+        /// # use std::num::NonZero;
+        /// #
+        #[doc = concat!("assert_eq!(NonZero::new(99", stringify!($Int), ").unwrap().ilog10(), 1);")]
+        #[doc = concat!("assert_eq!(NonZero::new(100", stringify!($Int), ").unwrap().ilog10(), 2);")]
+        #[doc = concat!("assert_eq!(NonZero::new(101", stringify!($Int), ").unwrap().ilog10(), 2);")]
         /// ```
         #[stable(feature = "int_log", since = "1.67.0")]
         #[rustc_const_stable(feature = "int_log", since = "1.67.0")]
@@ -1142,13 +1149,14 @@
         ///
         /// ```
         /// #![feature(num_midpoint)]
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
         ///
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")]
-        #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")]
-        #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")]
+        #[doc = concat!("let one = NonZero::new(1", stringify!($Int), ")?;")]
+        #[doc = concat!("let two = NonZero::new(2", stringify!($Int), ")?;")]
+        #[doc = concat!("let four = NonZero::new(4", stringify!($Int), ")?;")]
         ///
         /// assert_eq!(one.midpoint(four), two);
         /// assert_eq!(four.midpoint(one), two);
@@ -1179,9 +1187,9 @@
         /// Basic usage:
         ///
         /// ```
-        #[doc = concat!("let eight = std::num::", stringify!($Ty), "::new(8).unwrap();")]
+        #[doc = concat!("let eight = std::num::NonZero::new(8", stringify!($Int), ").unwrap();")]
         /// assert!(eight.is_power_of_two());
-        #[doc = concat!("let ten = std::num::", stringify!($Ty), "::new(10).unwrap();")]
+        #[doc = concat!("let ten = std::num::NonZero::new(10", stringify!($Int), ").unwrap();")]
         /// assert!(!ten.is_power_of_two());
         /// ```
         #[must_use]
@@ -1202,7 +1210,6 @@
     (
         Self = $Ty:ident,
         Primitive = signed $Int:ident,
-        UnsignedNonZero = $Uty:ident,
         UnsignedPrimitive = $Uint:ty,
     ) => {
         /// The smallest value that can be represented by this non-zero
@@ -1216,8 +1223,9 @@
         /// # Examples
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
-        #[doc = concat!("assert_eq!(", stringify!($Ty), "::MIN.get(), ", stringify!($Int), "::MIN);")]
+        /// # use std::num::NonZero;
+        /// #
+        #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::MIN.get(), ", stringify!($Int), "::MIN);")]
         /// ```
         #[stable(feature = "nonzero_min_max", since = "1.70.0")]
         pub const MIN: Self = Self::new(<$Int>::MIN).unwrap();
@@ -1233,8 +1241,9 @@
         /// # Examples
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
-        #[doc = concat!("assert_eq!(", stringify!($Ty), "::MAX.get(), ", stringify!($Int), "::MAX);")]
+        /// # use std::num::NonZero;
+        /// #
+        #[doc = concat!("assert_eq!(NonZero::<", stringify!($Int), ">::MAX.get(), ", stringify!($Int), "::MAX);")]
         /// ```
         #[stable(feature = "nonzero_min_max", since = "1.70.0")]
         pub const MAX: Self = Self::new(<$Int>::MAX).unwrap();
@@ -1246,11 +1255,12 @@
         /// # Example
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
-        #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
+        #[doc = concat!("let pos = NonZero::new(1", stringify!($Int), ")?;")]
+        #[doc = concat!("let neg = NonZero::new(-1", stringify!($Int), ")?;")]
         ///
         /// assert_eq!(pos, pos.abs());
         /// assert_eq!(pos, neg.abs());
@@ -1269,19 +1279,19 @@
 
         /// Checked absolute value.
         /// Checks for overflow and returns [`None`] if
-        #[doc = concat!("`self == ", stringify!($Ty), "::MIN`.")]
+        #[doc = concat!("`self == NonZero::<", stringify!($Int), ">::MIN`.")]
         /// The result cannot be zero.
         ///
         /// # Example
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
-        #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
-        #[doc = concat!("let min = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MIN)?;")]
+        #[doc = concat!("let pos = NonZero::new(1", stringify!($Int), ")?;")]
+        #[doc = concat!("let neg = NonZero::new(-1", stringify!($Int), ")?;")]
+        #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")]
         ///
         /// assert_eq!(Some(pos), neg.checked_abs());
         /// assert_eq!(None, min.checked_abs());
@@ -1309,13 +1319,13 @@
         /// # Example
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
-        #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
-        #[doc = concat!("let min = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MIN)?;")]
+        #[doc = concat!("let pos = NonZero::new(1", stringify!($Int), ")?;")]
+        #[doc = concat!("let neg = NonZero::new(-1", stringify!($Int), ")?;")]
+        #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")]
         ///
         /// assert_eq!((pos, false), pos.overflowing_abs());
         /// assert_eq!((pos, false), neg.overflowing_abs());
@@ -1343,17 +1353,15 @@
         /// # Example
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
-        #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
-        #[doc = concat!("let min = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MIN)?;")]
-        #[doc = concat!("let min_plus = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MIN + 1)?;")]
-        #[doc = concat!("let max = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MAX)?;")]
+        #[doc = concat!("let pos = NonZero::new(1", stringify!($Int), ")?;")]
+        #[doc = concat!("let neg = NonZero::new(-1", stringify!($Int), ")?;")]
+        #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")]
+        #[doc = concat!("let min_plus = NonZero::new(", stringify!($Int), "::MIN + 1)?;")]
+        #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")]
         ///
         /// assert_eq!(pos, pos.saturating_abs());
         /// assert_eq!(pos, neg.saturating_abs());
@@ -1378,15 +1386,14 @@
         /// # Example
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let pos = ", stringify!($Ty), "::new(1)?;")]
-        #[doc = concat!("let neg = ", stringify!($Ty), "::new(-1)?;")]
-        #[doc = concat!("let min = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MIN)?;")]
-        #[doc = concat!("# let max = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MAX)?;")]
+        #[doc = concat!("let pos = NonZero::new(1", stringify!($Int), ")?;")]
+        #[doc = concat!("let neg = NonZero::new(-1", stringify!($Int), ")?;")]
+        #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")]
+        #[doc = concat!("# let max = NonZero::new(", stringify!($Int), "::MAX)?;")]
         ///
         /// assert_eq!(pos, pos.wrapping_abs());
         /// assert_eq!(pos, neg.wrapping_abs());
@@ -1411,18 +1418,15 @@
         /// # Example
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
-        #[doc = concat!("# use std::num::", stringify!($Uty), ";")]
-        ///
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let u_pos = ", stringify!($Uty), "::new(1)?;")]
-        #[doc = concat!("let i_pos = ", stringify!($Ty), "::new(1)?;")]
-        #[doc = concat!("let i_neg = ", stringify!($Ty), "::new(-1)?;")]
-        #[doc = concat!("let i_min = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MIN)?;")]
-        #[doc = concat!("let u_max = ", stringify!($Uty), "::new(",
-                        stringify!($Uint), "::MAX / 2 + 1)?;")]
+        #[doc = concat!("let u_pos = NonZero::new(1", stringify!($Uint), ")?;")]
+        #[doc = concat!("let i_pos = NonZero::new(1", stringify!($Int), ")?;")]
+        #[doc = concat!("let i_neg = NonZero::new(-1", stringify!($Int), ")?;")]
+        #[doc = concat!("let i_min = NonZero::new(", stringify!($Int), "::MIN)?;")]
+        #[doc = concat!("let u_max = NonZero::new(", stringify!($Uint), "::MAX / 2 + 1)?;")]
         ///
         /// assert_eq!(u_pos, i_pos.unsigned_abs());
         /// assert_eq!(u_pos, i_neg.unsigned_abs());
@@ -1435,9 +1439,9 @@
         #[must_use = "this returns the result of the operation, \
                       without modifying the original"]
         #[inline]
-        pub const fn unsigned_abs(self) -> $Uty {
+        pub const fn unsigned_abs(self) -> NonZero<$Uint> {
             // SAFETY: absolute value of nonzero cannot yield zero values.
-            unsafe { $Uty::new_unchecked(self.get().unsigned_abs()) }
+            unsafe { NonZero::new_unchecked(self.get().unsigned_abs()) }
         }
 
         /// Returns `true` if `self` is positive and `false` if the
@@ -1446,11 +1450,12 @@
         /// # Example
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
-        #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
+        #[doc = concat!("let pos_five = NonZero::new(5", stringify!($Int), ")?;")]
+        #[doc = concat!("let neg_five = NonZero::new(-5", stringify!($Int), ")?;")]
         ///
         /// assert!(pos_five.is_positive());
         /// assert!(!neg_five.is_positive());
@@ -1471,11 +1476,12 @@
         /// # Example
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
-        #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
+        #[doc = concat!("let pos_five = NonZero::new(5", stringify!($Int), ")?;")]
+        #[doc = concat!("let neg_five = NonZero::new(-5", stringify!($Int), ")?;")]
         ///
         /// assert!(neg_five.is_negative());
         /// assert!(!pos_five.is_negative());
@@ -1491,18 +1497,18 @@
         }
 
         /// Checked negation. Computes `-self`,
-        #[doc = concat!("returning `None` if `self == ", stringify!($Ty), "::MIN`.")]
+        #[doc = concat!("returning `None` if `self == NonZero::<", stringify!($Int), ">::MIN`.")]
         ///
         /// # Example
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
-        #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
-        #[doc = concat!("let min = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MIN)?;")]
+        #[doc = concat!("let pos_five = NonZero::new(5", stringify!($Int), ")?;")]
+        #[doc = concat!("let neg_five = NonZero::new(-5", stringify!($Int), ")?;")]
+        #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")]
         ///
         /// assert_eq!(pos_five.checked_neg(), Some(neg_five));
         /// assert_eq!(min.checked_neg(), None);
@@ -1528,13 +1534,13 @@
         /// # Example
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
-        #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
-        #[doc = concat!("let min = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MIN)?;")]
+        #[doc = concat!("let pos_five = NonZero::new(5", stringify!($Int), ")?;")]
+        #[doc = concat!("let neg_five = NonZero::new(-5", stringify!($Int), ")?;")]
+        #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")]
         ///
         /// assert_eq!(pos_five.overflowing_neg(), (neg_five, false));
         /// assert_eq!(min.overflowing_neg(), (min, true));
@@ -1551,24 +1557,22 @@
         }
 
         /// Saturating negation. Computes `-self`,
-        #[doc = concat!("returning [`", stringify!($Ty), "::MAX`]")]
-        #[doc = concat!("if `self == ", stringify!($Ty), "::MIN`")]
+        #[doc = concat!("returning [`NonZero::<", stringify!($Int), ">::MAX`]")]
+        #[doc = concat!("if `self == NonZero::<", stringify!($Int), ">::MIN`")]
         /// instead of overflowing.
         ///
         /// # Example
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
-        #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
-        #[doc = concat!("let min = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MIN)?;")]
-        #[doc = concat!("let min_plus_one = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MIN + 1)?;")]
-        #[doc = concat!("let max = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MAX)?;")]
+        #[doc = concat!("let pos_five = NonZero::new(5", stringify!($Int), ")?;")]
+        #[doc = concat!("let neg_five = NonZero::new(-5", stringify!($Int), ")?;")]
+        #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")]
+        #[doc = concat!("let min_plus_one = NonZero::new(", stringify!($Int), "::MIN + 1)?;")]
+        #[doc = concat!("let max = NonZero::new(", stringify!($Int), "::MAX)?;")]
         ///
         /// assert_eq!(pos_five.saturating_neg(), neg_five);
         /// assert_eq!(min.saturating_neg(), max);
@@ -1595,13 +1599,13 @@
         /// # Example
         ///
         /// ```
-        #[doc = concat!("# use std::num::", stringify!($Ty), ";")]
+        /// # use std::num::NonZero;
+        /// #
         /// # fn main() { test().unwrap(); }
         /// # fn test() -> Option<()> {
-        #[doc = concat!("let pos_five = ", stringify!($Ty), "::new(5)?;")]
-        #[doc = concat!("let neg_five = ", stringify!($Ty), "::new(-5)?;")]
-        #[doc = concat!("let min = ", stringify!($Ty), "::new(",
-                        stringify!($Int), "::MIN)?;")]
+        #[doc = concat!("let pos_five = NonZero::new(5", stringify!($Int), ")?;")]
+        #[doc = concat!("let neg_five = NonZero::new(-5", stringify!($Int), ")?;")]
+        #[doc = concat!("let min = NonZero::new(", stringify!($Int), "::MIN)?;")]
         ///
         /// assert_eq!(pos_five.wrapping_neg(), neg_five);
         /// assert_eq!(min.wrapping_neg(), min);
@@ -1662,41 +1666,35 @@
 nonzero_integer! {
     Self = NonZeroI8,
     Primitive = signed i8,
-    UnsignedNonZero = NonZeroU8,
     UnsignedPrimitive = u8,
 }
 
 nonzero_integer! {
     Self = NonZeroI16,
     Primitive = signed i16,
-    UnsignedNonZero = NonZeroU16,
     UnsignedPrimitive = u16,
 }
 
 nonzero_integer! {
     Self = NonZeroI32,
     Primitive = signed i32,
-    UnsignedNonZero = NonZeroU32,
     UnsignedPrimitive = u32,
 }
 
 nonzero_integer! {
     Self = NonZeroI64,
     Primitive = signed i64,
-    UnsignedNonZero = NonZeroU64,
     UnsignedPrimitive = u64,
 }
 
 nonzero_integer! {
     Self = NonZeroI128,
     Primitive = signed i128,
-    UnsignedNonZero = NonZeroU128,
     UnsignedPrimitive = u128,
 }
 
 nonzero_integer! {
     Self = NonZeroIsize,
     Primitive = signed isize,
-    UnsignedNonZero = NonZeroUsize,
     UnsignedPrimitive = usize,
 }
diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs
index 48a96c5..446d065 100644
--- a/library/core/src/num/uint_macros.rs
+++ b/library/core/src/num/uint_macros.rs
@@ -584,11 +584,11 @@
             // Thus, rather than using `overflowing_sub` that produces a wrapping
             // subtraction, check it ourself so we can use an unchecked one.
 
-            if self >= rhs {
+            if self < rhs {
+                None
+            } else {
                 // SAFETY: just checked this can't overflow
                 Some(unsafe { intrinsics::unchecked_sub(self, rhs) })
-            } else {
-                None
             }
         }
 
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index d859736..8283fdc 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1467,8 +1467,9 @@
 /// For all types, `T: ?Sized`, and for all `t: &T` or `t: &mut T`, when such values cross an API
 /// boundary, the following invariants must generally be upheld:
 ///
+/// * `t` is non-null
 /// * `t` is aligned to `align_of_val(t)`
-/// * `t` is dereferenceable for `size_of_val(t)` many bytes
+/// * if `size_of_val(t) > 0`, then `t` is dereferenceable for `size_of_val(t)` many bytes
 ///
 /// If `t` points at address `a`, being "dereferenceable" for N bytes means that the memory range
 /// `[a, a + N)` is all contained within a single [allocated object].
diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs
index 73bb256..c8065b2 100644
--- a/library/core/src/ptr/const_ptr.rs
+++ b/library/core/src/ptr/const_ptr.rs
@@ -465,8 +465,9 @@
     /// If any of the following conditions are violated, the result is Undefined
     /// Behavior:
     ///
-    /// * Both the starting and resulting pointer must be either in bounds or one
-    ///   byte past the end of the same [allocated object].
+    /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
+    ///   pointer must be either in bounds or at the end of the same [allocated object].
+    ///   (If it is zero, then the function is always well-defined.)
     ///
     /// * The computed offset, **in bytes**, cannot overflow an `isize`.
     ///
@@ -676,11 +677,11 @@
     /// If any of the following conditions are violated, the result is Undefined
     /// Behavior:
     ///
-    /// * Both `self` and `origin` must be either in bounds or one
-    ///   byte past the end of the same [allocated object].
+    /// * `self` and `origin` must either
     ///
-    /// * Both pointers must be *derived from* a pointer to the same object.
-    ///   (See below for an example.)
+    ///   * both be *derived from* a pointer to the same [allocated object], and the memory range between
+    ///     the two pointers must be either empty or in bounds of that object. (See below for an example.)
+    ///   * or both be derived from an integer literal/constant, and point to the same address.
     ///
     /// * The distance between the pointers, in bytes, must be an exact multiple
     ///   of the size of `T`.
@@ -951,8 +952,9 @@
     /// If any of the following conditions are violated, the result is Undefined
     /// Behavior:
     ///
-    /// * Both the starting and resulting pointer must be either in bounds or one
-    ///   byte past the end of the same [allocated object].
+    /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
+    ///   pointer must be either in bounds or at the end of the same [allocated object].
+    ///   (If it is zero, then the function is always well-defined.)
     ///
     /// * The computed offset, **in bytes**, cannot overflow an `isize`.
     ///
@@ -1035,8 +1037,9 @@
     /// If any of the following conditions are violated, the result is Undefined
     /// Behavior:
     ///
-    /// * Both the starting and resulting pointer must be either in bounds or one
-    ///   byte past the end of the same [allocated object].
+    /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
+    ///   pointer must be either in bounds or at the end of the same [allocated object].
+    ///   (If it is zero, then the function is always well-defined.)
     ///
     /// * The computed offset cannot exceed `isize::MAX` **bytes**.
     ///
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 5f38158..d2bbdc8 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -15,18 +15,13 @@
 //! The precise rules for validity are not determined yet. The guarantees that are
 //! provided at this point are very minimal:
 //!
-//! * A [null] pointer is *never* valid, not even for accesses of [size zero][zst].
+//! * For operations of [size zero][zst], *every* pointer is valid, including the [null] pointer.
+//!   The following points are only concerned with non-zero-sized accesses.
+//! * A [null] pointer is *never* valid.
 //! * For a pointer to be valid, it is necessary, but not always sufficient, that the pointer
 //!   be *dereferenceable*: the memory range of the given size starting at the pointer must all be
 //!   within the bounds of a single allocated object. Note that in Rust,
 //!   every (stack-allocated) variable is considered a separate allocated object.
-//! * Even for operations of [size zero][zst], the pointer must not be pointing to deallocated
-//!   memory, i.e., deallocation makes pointers invalid even for zero-sized operations. However,
-//!   casting any non-zero integer *literal* to a pointer is valid for zero-sized accesses, even if
-//!   some memory happens to exist at that address and gets deallocated. This corresponds to writing
-//!   your own allocator: allocating zero-sized objects is not very hard. The canonical way to
-//!   obtain a pointer that is valid for zero-sized accesses is [`NonNull::dangling`].
-//FIXME: mention `ptr::dangling` above, once it is stable.
 //! * All accesses performed by functions in this module are *non-atomic* in the sense
 //!   of [atomic operations] used to synchronize between threads. This means it is
 //!   undefined behavior to perform two concurrent accesses to the same location from different
@@ -63,11 +58,39 @@
 //!
 //! ## Allocated object
 //!
-//! For several operations, such as [`offset`] or field projections (`expr.field`), the notion of an
-//! "allocated object" becomes relevant. An allocated object is a contiguous region of memory.
-//! Common examples of allocated objects include stack-allocated variables (each variable is a
-//! separate allocated object), heap allocations (each allocation created by the global allocator is
-//! a separate allocated object), and `static` variables.
+//! An *allocated object* is a subset of program memory which is addressable
+//! from Rust, and within which pointer arithmetic is possible. Examples of
+//! allocated objects include heap allocations, stack-allocated variables,
+//! statics, and consts. The safety preconditions of some Rust operations -
+//! such as `offset` and field projections (`expr.field`) - are defined in
+//! terms of the allocated objects on which they operate.
+//!
+//! An allocated object has a base address, a size, and a set of memory
+//! addresses. It is possible for an allocated object to have zero size, but
+//! such an allocated object will still have a base address. The base address
+//! of an allocated object is not necessarily unique. While it is currently the
+//! case that an allocated object always has a set of memory addresses which is
+//! fully contiguous (i.e., has no "holes"), there is no guarantee that this
+//! will not change in the future.
+//!
+//! For any allocated object with `base` address, `size`, and a set of
+//! `addresses`, the following are guaranteed:
+//! - For all addresses `a` in `addresses`, `a` is in the range `base .. (base +
+//!   size)` (note that this requires `a < base + size`, not `a <= base + size`)
+//! - `base` is not equal to [`null()`] (i.e., the address with the numerical
+//!   value 0)
+//! - `base + size <= usize::MAX`
+//! - `size <= isize::MAX`
+//!
+//! As a consequence of these guarantees, given any address `a` within the set
+//! of addresses of an allocated object:
+//! - It is guaranteed that `a - base` does not overflow `isize`
+//! - It is guaranteed that `a - base` is non-negative
+//! - It is guaranteed that, given `o = a - base` (i.e., the offset of `a` within
+//!   the allocated object), `base + o` will not wrap around the address space (in
+//!   other words, will not overflow `usize`)
+//!
+//! [`null()`]: null
 //!
 //! # Strict Provenance
 //!
@@ -812,7 +835,7 @@
 #[rustc_allow_const_fn_unstable(ptr_metadata)]
 #[rustc_diagnostic_item = "ptr_slice_from_raw_parts"]
 pub const fn slice_from_raw_parts<T>(data: *const T, len: usize) -> *const [T] {
-    from_raw_parts(data.cast(), len)
+    intrinsics::aggregate_raw_ptr(data, len)
 }
 
 /// Forms a raw mutable slice from a pointer and a length.
@@ -858,7 +881,7 @@
 #[rustc_const_unstable(feature = "const_slice_from_raw_parts_mut", issue = "67456")]
 #[rustc_diagnostic_item = "ptr_slice_from_raw_parts_mut"]
 pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] {
-    from_raw_parts_mut(data.cast(), len)
+    intrinsics::aggregate_raw_ptr(data, len)
 }
 
 /// Swaps the values at two mutable locations of the same type, without
diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs
index b679305..c539534 100644
--- a/library/core/src/ptr/mut_ptr.rs
+++ b/library/core/src/ptr/mut_ptr.rs
@@ -187,7 +187,7 @@
     ///
     /// This is similar to `self as usize`, which semantically discards *provenance* and
     /// *address-space* information. However, unlike `self as usize`, casting the returned address
-    /// back to a pointer yields yields a [pointer without provenance][without_provenance_mut], which is undefined
+    /// back to a pointer yields a [pointer without provenance][without_provenance_mut], which is undefined
     /// behavior to dereference. To properly restore the lost information and obtain a
     /// dereferenceable pointer, use [`with_addr`][pointer::with_addr] or
     /// [`map_addr`][pointer::map_addr].
@@ -480,8 +480,9 @@
     /// If any of the following conditions are violated, the result is Undefined
     /// Behavior:
     ///
-    /// * Both the starting and resulting pointer must be either in bounds or one
-    ///   byte past the end of the same [allocated object].
+    /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
+    ///   pointer must be either in bounds or at the end of the same [allocated object].
+    ///   (If it is zero, then the function is always well-defined.)
     ///
     /// * The computed offset, **in bytes**, cannot overflow an `isize`.
     ///
@@ -904,11 +905,11 @@
     /// If any of the following conditions are violated, the result is Undefined
     /// Behavior:
     ///
-    /// * Both `self` and `origin` must be either in bounds or one
-    ///   byte past the end of the same [allocated object].
+    /// * `self` and `origin` must either
     ///
-    /// * Both pointers must be *derived from* a pointer to the same object.
-    ///   (See below for an example.)
+    ///   * both be *derived from* a pointer to the same [allocated object], and the memory range between
+    ///     the two pointers must be either empty or in bounds of that object. (See below for an example.)
+    ///   * or both be derived from an integer literal/constant, and point to the same address.
     ///
     /// * The distance between the pointers, in bytes, must be an exact multiple
     ///   of the size of `T`.
@@ -1095,8 +1096,9 @@
     /// If any of the following conditions are violated, the result is Undefined
     /// Behavior:
     ///
-    /// * Both the starting and resulting pointer must be either in bounds or one
-    ///   byte past the end of the same [allocated object].
+    /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
+    ///   pointer must be either in bounds or at the end of the same [allocated object].
+    ///   (If it is zero, then the function is always well-defined.)
     ///
     /// * The computed offset, **in bytes**, cannot overflow an `isize`.
     ///
@@ -1179,8 +1181,9 @@
     /// If any of the following conditions are violated, the result is Undefined
     /// Behavior:
     ///
-    /// * Both the starting and resulting pointer must be either in bounds or one
-    ///   byte past the end of the same [allocated object].
+    /// * If the computed offset, **in bytes**, is non-zero, then both the starting and resulting
+    ///   pointer must be either in bounds or at the end of the same [allocated object].
+    ///   (If it is zero, then the function is always well-defined.)
     ///
     /// * The computed offset cannot exceed `isize::MAX` **bytes**.
     ///
diff --git a/library/core/src/result.rs b/library/core/src/result.rs
index b2b627f..4c6dc4b 100644
--- a/library/core/src/result.rs
+++ b/library/core/src/result.rs
@@ -45,25 +45,29 @@
 //! that make working with it more succinct.
 //!
 //! ```
+//! // The `is_ok` and `is_err` methods do what they say.
 //! let good_result: Result<i32, i32> = Ok(10);
 //! let bad_result: Result<i32, i32> = Err(10);
-//!
-//! // The `is_ok` and `is_err` methods do what they say.
 //! assert!(good_result.is_ok() && !good_result.is_err());
 //! assert!(bad_result.is_err() && !bad_result.is_ok());
 //!
-//! // `map` consumes the `Result` and produces another.
+//! // `map` and `map_err` consume the `Result` and produce another.
 //! let good_result: Result<i32, i32> = good_result.map(|i| i + 1);
-//! let bad_result: Result<i32, i32> = bad_result.map(|i| i - 1);
+//! let bad_result: Result<i32, i32> = bad_result.map_err(|i| i - 1);
+//! assert_eq!(good_result, Ok(11));
+//! assert_eq!(bad_result, Err(9));
 //!
 //! // Use `and_then` to continue the computation.
 //! let good_result: Result<bool, i32> = good_result.and_then(|i| Ok(i == 11));
+//! assert_eq!(good_result, Ok(true));
 //!
 //! // Use `or_else` to handle the error.
 //! let bad_result: Result<i32, i32> = bad_result.or_else(|i| Ok(i + 20));
+//! assert_eq!(bad_result, Ok(29));
 //!
 //! // Consume the result and return the contents with `unwrap`.
 //! let final_awesome_result = good_result.unwrap();
+//! assert!(final_awesome_result)
 //! ```
 //!
 //! # Results must be used
diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs
index 5c4f0bf..8ad0452 100644
--- a/library/core/src/slice/ascii.rs
+++ b/library/core/src/slice/ascii.rs
@@ -114,18 +114,17 @@
     /// Returns a byte slice with leading ASCII whitespace bytes removed.
     ///
     /// 'Whitespace' refers to the definition used by
-    /// `u8::is_ascii_whitespace`.
+    /// [`u8::is_ascii_whitespace`].
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(byte_slice_trim_ascii)]
-    ///
     /// assert_eq!(b" \t hello world\n".trim_ascii_start(), b"hello world\n");
     /// assert_eq!(b"  ".trim_ascii_start(), b"");
     /// assert_eq!(b"".trim_ascii_start(), b"");
     /// ```
-    #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")]
+    #[stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn trim_ascii_start(&self) -> &[u8] {
         let mut bytes = self;
@@ -144,18 +143,17 @@
     /// Returns a byte slice with trailing ASCII whitespace bytes removed.
     ///
     /// 'Whitespace' refers to the definition used by
-    /// `u8::is_ascii_whitespace`.
+    /// [`u8::is_ascii_whitespace`].
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(byte_slice_trim_ascii)]
-    ///
     /// assert_eq!(b"\r hello world\n ".trim_ascii_end(), b"\r hello world");
     /// assert_eq!(b"  ".trim_ascii_end(), b"");
     /// assert_eq!(b"".trim_ascii_end(), b"");
     /// ```
-    #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")]
+    #[stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn trim_ascii_end(&self) -> &[u8] {
         let mut bytes = self;
@@ -175,18 +173,17 @@
     /// removed.
     ///
     /// 'Whitespace' refers to the definition used by
-    /// `u8::is_ascii_whitespace`.
+    /// [`u8::is_ascii_whitespace`].
     ///
     /// # Examples
     ///
     /// ```
-    /// #![feature(byte_slice_trim_ascii)]
-    ///
     /// assert_eq!(b"\r hello world\n ".trim_ascii(), b"hello world");
     /// assert_eq!(b"  ".trim_ascii(), b"");
     /// assert_eq!(b"".trim_ascii(), b"");
     /// ```
-    #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")]
+    #[stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn trim_ascii(&self) -> &[u8] {
         self.trim_ascii_start().trim_ascii_end()
diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs
index d7d4f90..96fc87a 100644
--- a/library/core/src/slice/iter.rs
+++ b/library/core/src/slice/iter.rs
@@ -16,6 +16,9 @@
 
 use super::{from_raw_parts, from_raw_parts_mut};
 
+#[stable(feature = "boxed_slice_into_iter", since = "CURRENT_RUSTC_VERSION")]
+impl<T> !Iterator for [T] {}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, T> IntoIterator for &'a [T] {
     type Item = &'a T;
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 133cde8..f82f965 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -1337,8 +1337,10 @@
     #[must_use]
     pub const fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T]) {
         assert!(N != 0, "chunk size must be non-zero");
-        let len = self.len() / N;
-        let (multiple_of_n, remainder) = self.split_at(len * N);
+        let len_rounded_down = self.len() / N * N;
+        // SAFETY: The rounded-down value is always the same or smaller than the
+        // original length, and thus must be in-bounds of the slice.
+        let (multiple_of_n, remainder) = unsafe { self.split_at_unchecked(len_rounded_down) };
         // SAFETY: We already panicked for zero, and ensured by construction
         // that the length of the subslice is a multiple of N.
         let array_slice = unsafe { multiple_of_n.as_chunks_unchecked() };
@@ -1487,8 +1489,10 @@
     #[must_use]
     pub const fn as_chunks_mut<const N: usize>(&mut self) -> (&mut [[T; N]], &mut [T]) {
         assert!(N != 0, "chunk size must be non-zero");
-        let len = self.len() / N;
-        let (multiple_of_n, remainder) = self.split_at_mut(len * N);
+        let len_rounded_down = self.len() / N * N;
+        // SAFETY: The rounded-down value is always the same or smaller than the
+        // original length, and thus must be in-bounds of the slice.
+        let (multiple_of_n, remainder) = unsafe { self.split_at_mut_unchecked(len_rounded_down) };
         // SAFETY: We already panicked for zero, and ensured by construction
         // that the length of the subslice is a multiple of N.
         let array_slice = unsafe { multiple_of_n.as_chunks_unchecked_mut() };
@@ -4529,21 +4533,21 @@
     /// ```
     /// #![feature(slice_flatten)]
     ///
-    /// assert_eq!([[1, 2, 3], [4, 5, 6]].flatten(), &[1, 2, 3, 4, 5, 6]);
+    /// assert_eq!([[1, 2, 3], [4, 5, 6]].as_flattened(), &[1, 2, 3, 4, 5, 6]);
     ///
     /// assert_eq!(
-    ///     [[1, 2, 3], [4, 5, 6]].flatten(),
-    ///     [[1, 2], [3, 4], [5, 6]].flatten(),
+    ///     [[1, 2, 3], [4, 5, 6]].as_flattened(),
+    ///     [[1, 2], [3, 4], [5, 6]].as_flattened(),
     /// );
     ///
     /// let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []];
-    /// assert!(slice_of_empty_arrays.flatten().is_empty());
+    /// assert!(slice_of_empty_arrays.as_flattened().is_empty());
     ///
     /// let empty_slice_of_arrays: &[[u32; 10]] = &[];
-    /// assert!(empty_slice_of_arrays.flatten().is_empty());
+    /// assert!(empty_slice_of_arrays.as_flattened().is_empty());
     /// ```
     #[unstable(feature = "slice_flatten", issue = "95629")]
-    pub const fn flatten(&self) -> &[T] {
+    pub const fn as_flattened(&self) -> &[T] {
         let len = if T::IS_ZST {
             self.len().checked_mul(N).expect("slice len overflow")
         } else {
@@ -4577,11 +4581,11 @@
     /// }
     ///
     /// let mut array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
-    /// add_5_to_all(array.flatten_mut());
+    /// add_5_to_all(array.as_flattened_mut());
     /// assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]);
     /// ```
     #[unstable(feature = "slice_flatten", issue = "95629")]
-    pub fn flatten_mut(&mut self) -> &mut [T] {
+    pub fn as_flattened_mut(&mut self) -> &mut [T] {
         let len = if T::IS_ZST {
             self.len().checked_mul(N).expect("slice len overflow")
         } else {
diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs
index b6f6590..669cdc9 100644
--- a/library/core/src/str/mod.rs
+++ b/library/core/src/str/mod.rs
@@ -2531,15 +2531,14 @@
     /// # Examples
     ///
     /// ```
-    /// #![feature(byte_slice_trim_ascii)]
-    ///
     /// assert_eq!(" \t \u{3000}hello world\n".trim_ascii_start(), "\u{3000}hello world\n");
     /// assert_eq!("  ".trim_ascii_start(), "");
     /// assert_eq!("".trim_ascii_start(), "");
     /// ```
-    #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")]
     #[must_use = "this returns the trimmed string as a new slice, \
                   without modifying the original"]
+    #[stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn trim_ascii_start(&self) -> &str {
         // SAFETY: Removing ASCII characters from a `&str` does not invalidate
@@ -2557,15 +2556,14 @@
     /// # Examples
     ///
     /// ```
-    /// #![feature(byte_slice_trim_ascii)]
-    ///
     /// assert_eq!("\r hello world\u{3000}\n ".trim_ascii_end(), "\r hello world\u{3000}");
     /// assert_eq!("  ".trim_ascii_end(), "");
     /// assert_eq!("".trim_ascii_end(), "");
     /// ```
-    #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")]
     #[must_use = "this returns the trimmed string as a new slice, \
                   without modifying the original"]
+    #[stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn trim_ascii_end(&self) -> &str {
         // SAFETY: Removing ASCII characters from a `&str` does not invalidate
@@ -2584,15 +2582,14 @@
     /// # Examples
     ///
     /// ```
-    /// #![feature(byte_slice_trim_ascii)]
-    ///
     /// assert_eq!("\r hello world\n ".trim_ascii(), "hello world");
     /// assert_eq!("  ".trim_ascii(), "");
     /// assert_eq!("".trim_ascii(), "");
     /// ```
-    #[unstable(feature = "byte_slice_trim_ascii", issue = "94035")]
     #[must_use = "this returns the trimmed string as a new slice, \
                   without modifying the original"]
+    #[stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")]
+    #[rustc_const_stable(feature = "byte_slice_trim_ascii", since = "CURRENT_RUSTC_VERSION")]
     #[inline]
     pub const fn trim_ascii(&self) -> &str {
         // SAFETY: Removing ASCII characters from a `&str` does not invalidate
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index 72f6a3b..88fe29c 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -43,11 +43,15 @@
 #[rustc_layout_scalar_valid_range_end(999_999_999)]
 struct Nanoseconds(u32);
 
+impl Nanoseconds {
+    // SAFETY: 0 is within the valid range
+    const ZERO: Self = unsafe { Nanoseconds(0) };
+}
+
 impl Default for Nanoseconds {
     #[inline]
     fn default() -> Self {
-        // SAFETY: 0 is within the valid range
-        unsafe { Nanoseconds(0) }
+        Self::ZERO
     }
 }
 
@@ -236,7 +240,7 @@
     #[inline]
     #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_secs(secs: u64) -> Duration {
-        Duration::new(secs, 0)
+        Duration { secs, nanos: Nanoseconds::ZERO }
     }
 
     /// Creates a new `Duration` from the specified number of milliseconds.
@@ -256,7 +260,13 @@
     #[inline]
     #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_millis(millis: u64) -> Duration {
-        Duration::new(millis / MILLIS_PER_SEC, ((millis % MILLIS_PER_SEC) as u32) * NANOS_PER_MILLI)
+        let secs = millis / MILLIS_PER_SEC;
+        let subsec_millis = (millis % MILLIS_PER_SEC) as u32;
+        // SAFETY: (x % 1_000) * 1_000_000 < 1_000_000_000
+        //         => x % 1_000 < 1_000
+        let subsec_nanos = unsafe { Nanoseconds(subsec_millis * NANOS_PER_MILLI) };
+
+        Duration { secs, nanos: subsec_nanos }
     }
 
     /// Creates a new `Duration` from the specified number of microseconds.
@@ -276,7 +286,13 @@
     #[inline]
     #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_micros(micros: u64) -> Duration {
-        Duration::new(micros / MICROS_PER_SEC, ((micros % MICROS_PER_SEC) as u32) * NANOS_PER_MICRO)
+        let secs = micros / MICROS_PER_SEC;
+        let subsec_micros = (micros % MICROS_PER_SEC) as u32;
+        // SAFETY: (x % 1_000_000) * 1_000 < 1_000_000_000
+        //         => x % 1_000_000 < 1_000_000
+        let subsec_nanos = unsafe { Nanoseconds(subsec_micros * NANOS_PER_MICRO) };
+
+        Duration { secs, nanos: subsec_nanos }
     }
 
     /// Creates a new `Duration` from the specified number of nanoseconds.
@@ -301,7 +317,13 @@
     #[inline]
     #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")]
     pub const fn from_nanos(nanos: u64) -> Duration {
-        Duration::new(nanos / (NANOS_PER_SEC as u64), (nanos % (NANOS_PER_SEC as u64)) as u32)
+        const NANOS_PER_SEC: u64 = self::NANOS_PER_SEC as u64;
+        let secs = nanos / NANOS_PER_SEC;
+        let subsec_nanos = (nanos % NANOS_PER_SEC) as u32;
+        // SAFETY: x % 1_000_000_000 < 1_000_000_000
+        let subsec_nanos = unsafe { Nanoseconds(subsec_nanos) };
+
+        Duration { secs, nanos: subsec_nanos }
     }
 
     /// Creates a new `Duration` from the specified number of weeks.
diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs
index ffe8ffc..c91ac2f 100644
--- a/library/core/tests/slice.rs
+++ b/library/core/tests/slice.rs
@@ -2609,14 +2609,14 @@
 #[should_panic = "slice len overflow"]
 fn test_flatten_size_overflow() {
     let x = &[[(); usize::MAX]; 2][..];
-    let _ = x.flatten();
+    let _ = x.as_flattened();
 }
 
 #[test]
 #[should_panic = "slice len overflow"]
 fn test_flatten_mut_size_overflow() {
     let x = &mut [[(); usize::MAX]; 2][..];
-    let _ = x.flatten_mut();
+    let _ = x.as_flattened_mut();
 }
 
 #[test]
diff --git a/library/portable-simd/crates/core_simd/src/ops.rs b/library/portable-simd/crates/core_simd/src/ops.rs
index d8e10ee..dd7303a 100644
--- a/library/portable-simd/crates/core_simd/src/ops.rs
+++ b/library/portable-simd/crates/core_simd/src/ops.rs
@@ -122,7 +122,7 @@
                     #[inline]
                     #[must_use = "operator returns a new vector without mutating the inputs"]
                     // TODO: only useful for int Div::div, but we hope that this
-                    // will essentially always always get inlined anyway.
+                    // will essentially always get inlined anyway.
                     #[track_caller]
                     fn $call(self, rhs: Self) -> Self::Output {
                         $macro_impl!(self, rhs, $inner, $scalar)
diff --git a/library/profiler_builtins/Cargo.toml b/library/profiler_builtins/Cargo.toml
index 937149f..5b10fb5 100644
--- a/library/profiler_builtins/Cargo.toml
+++ b/library/profiler_builtins/Cargo.toml
@@ -13,4 +13,4 @@
 compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] }
 
 [build-dependencies]
-cc = "1.0.90"
+cc = "1.0.97"
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 52729ba..5b36867 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -33,9 +33,6 @@
 [target.'cfg(not(all(windows, target_env = "msvc")))'.dependencies]
 libc = { version = "0.2.153", default-features = false, features = ['rustc-dep-of-std'], public = true }
 
-[target.'cfg(all(windows, target_env = "msvc"))'.dependencies]
-libc = { version = "0.2.153", default-features = false }
-
 [target.'cfg(all(not(target_os = "aix"), not(all(windows, target_env = "msvc", not(target_vendor = "uwp")))))'.dependencies]
 object = { version = "0.32.0", default-features = false, optional = true, features = ['read_core', 'elf', 'macho', 'pe', 'unaligned', 'archive'] }
 
@@ -81,6 +78,8 @@
 
 # Make panics and failed asserts immediately abort without formatting any message
 panic_immediate_abort = ["core/panic_immediate_abort", "alloc/panic_immediate_abort"]
+# Choose algorithms that are optimized for binary size instead of runtime performance
+optimize_for_size = ["core/optimize_for_size", "alloc/optimize_for_size"]
 
 # Enable std_detect default features for stdarch/crates/std_detect:
 # https://github.com/rust-lang/stdarch/blob/master/crates/std_detect/Cargo.toml
diff --git a/library/std/src/f128.rs b/library/std/src/f128.rs
index 4710d7c..491235a 100644
--- a/library/std/src/f128.rs
+++ b/library/std/src/f128.rs
@@ -7,5 +7,29 @@
 #[cfg(test)]
 mod tests;
 
+#[cfg(not(test))]
+use crate::intrinsics;
+
 #[unstable(feature = "f128", issue = "116909")]
 pub use core::f128::consts;
+
+#[cfg(not(test))]
+impl f128 {
+    /// Raises a number to an integer power.
+    ///
+    /// Using this function is generally faster than using `powf`.
+    /// It might have a different sequence of rounding operations than `powf`,
+    /// so the results are not guaranteed to agree.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and
+    /// can even differ within the same execution from one invocation to the next.
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f128", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn powi(self, n: i32) -> f128 {
+        unsafe { intrinsics::powif128(self, n) }
+    }
+}
diff --git a/library/std/src/f16.rs b/library/std/src/f16.rs
index c36f9f5..1cb655f 100644
--- a/library/std/src/f16.rs
+++ b/library/std/src/f16.rs
@@ -7,5 +7,29 @@
 #[cfg(test)]
 mod tests;
 
+#[cfg(not(test))]
+use crate::intrinsics;
+
 #[unstable(feature = "f16", issue = "116909")]
 pub use core::f16::consts;
+
+#[cfg(not(test))]
+impl f16 {
+    /// Raises a number to an integer power.
+    ///
+    /// Using this function is generally faster than using `powf`.
+    /// It might have a different sequence of rounding operations than `powf`,
+    /// so the results are not guaranteed to agree.
+    ///
+    /// # Unspecified precision
+    ///
+    /// The precision of this function is non-deterministic. This means it varies by platform, Rust version, and
+    /// can even differ within the same execution from one invocation to the next.
+    #[inline]
+    #[rustc_allow_incoherent_impl]
+    #[unstable(feature = "f16", issue = "116909")]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    pub fn powi(self, n: i32) -> f16 {
+        unsafe { intrinsics::powif16(self, n) }
+    }
+}
diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs
index 37492e9..a1a8b2a 100644
--- a/library/std/src/io/cursor.rs
+++ b/library/std/src/io/cursor.rs
@@ -328,7 +328,7 @@
     fn read_buf(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
         let prev_written = cursor.written();
 
-        Read::read_buf(&mut self.fill_buf()?, cursor.reborrow())?;
+        Read::read_buf(&mut self.remaining_slice(), cursor.reborrow())?;
 
         self.pos += (cursor.written() - prev_written) as u64;
 
@@ -352,17 +352,24 @@
     }
 
     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
-        let n = buf.len();
-        Read::read_exact(&mut self.remaining_slice(), buf)?;
-        self.pos += n as u64;
-        Ok(())
+        let result = Read::read_exact(&mut self.remaining_slice(), buf);
+
+        match result {
+            Ok(_) => self.pos += buf.len() as u64,
+            // The only possible error condition is EOF, so place the cursor at "EOF"
+            Err(_) => self.pos = self.inner.as_ref().len() as u64,
+        }
+
+        result
     }
 
-    fn read_buf_exact(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
-        let n = cursor.capacity();
-        Read::read_buf_exact(&mut self.remaining_slice(), cursor)?;
-        self.pos += n as u64;
-        Ok(())
+    fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
+        let prev_written = cursor.written();
+
+        let result = Read::read_buf_exact(&mut self.remaining_slice(), cursor.reborrow());
+        self.pos += (cursor.written() - prev_written) as u64;
+
+        result
     }
 
     fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs
index 46f04c7..a8a2e94 100644
--- a/library/std/src/io/impls.rs
+++ b/library/std/src/io/impls.rs
@@ -287,6 +287,9 @@
     #[inline]
     fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
         if buf.len() > self.len() {
+            // `read_exact` makes no promise about the content of `buf` if it
+            // fails so don't bother about that.
+            *self = &self[self.len()..];
             return Err(io::Error::READ_EXACT_EOF);
         }
         let (a, b) = self.split_at(buf.len());
@@ -307,6 +310,9 @@
     #[inline]
     fn read_buf_exact(&mut self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
         if cursor.capacity() > self.len() {
+            // Append everything we can to the cursor.
+            cursor.append(*self);
+            *self = &self[self.len()..];
             return Err(io::Error::READ_EXACT_EOF);
         }
         let (a, b) = self.split_at(cursor.capacity());
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index af05515..f55ec15 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -1839,7 +1839,11 @@
                 if output.error.is_err() {
                     output.error
                 } else {
-                    Err(error::const_io_error!(ErrorKind::Uncategorized, "formatter error"))
+                    // This shouldn't happen: the underlying stream did not error, but somehow
+                    // the formatter still errored?
+                    panic!(
+                        "a formatting trait implementation returned an error when the underlying stream did not"
+                    );
                 }
             }
         }
@@ -2040,7 +2044,6 @@
     /// # Example
     ///
     /// ```no_run
-    /// #![feature(seek_seek_relative)]
     /// use std::{
     ///     io::{self, Seek},
     ///     fs::File,
@@ -2055,7 +2058,7 @@
     /// ```
     ///
     /// [`BufReader`]: crate::io::BufReader
-    #[unstable(feature = "seek_seek_relative", issue = "117374")]
+    #[stable(feature = "seek_seek_relative", since = "CURRENT_RUSTC_VERSION")]
     fn seek_relative(&mut self, offset: i64) -> Result<()> {
         self.seek(SeekFrom::Current(offset))?;
         Ok(())
diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs
index 07fa925..c8968b7 100644
--- a/library/std/src/io/stdio.rs
+++ b/library/std/src/io/stdio.rs
@@ -1161,7 +1161,41 @@
     /// starting with `msys-` or `cygwin-` and ending in `-pty` will be considered terminals.
     /// Note that this [may change in the future][changes].
     ///
+    /// # Examples
+    ///
+    /// An example of a type for which `IsTerminal` is implemented is [`Stdin`]:
+    ///
+    /// ```no_run
+    /// use std::io::{self, IsTerminal, Write};
+    ///
+    /// fn main() -> io::Result<()> {
+    ///     let stdin = io::stdin();
+    ///
+    ///     // Indicate that the user is prompted for input, if this is a terminal.
+    ///     if stdin.is_terminal() {
+    ///         print!("> ");
+    ///         io::stdout().flush()?;
+    ///     }
+    ///
+    ///     let mut name = String::new();
+    ///     let _ = stdin.read_line(&mut name)?;
+    ///
+    ///     println!("Hello {}", name.trim_end());
+    ///
+    ///     Ok(())
+    /// }
+    /// ```
+    ///
+    /// The example can be run in two ways:
+    ///
+    /// - If you run this example by piping some text to it, e.g. `echo "foo" | path/to/executable`
+    ///   it will print: `Hello foo`.
+    /// - If you instead run the example interactively by running the executable directly, it will
+    ///   panic with the message "Expected input to be piped to the process".
+    ///
+    ///
     /// [changes]: io#platform-specific-behavior
+    /// [`Stdin`]: crate::io::Stdin
     #[stable(feature = "is_terminal", since = "1.70.0")]
     fn is_terminal(&self) -> bool;
 }
diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs
index 090a091..a2c1c43 100644
--- a/library/std/src/io/tests.rs
+++ b/library/std/src/io/tests.rs
@@ -653,6 +653,38 @@
     let _ = reader.read(&mut buffer[..]);
 }
 
+#[test]
+fn slice_read_exact_eof() {
+    let slice = &b"123456"[..];
+
+    let mut r = slice;
+    assert!(r.read_exact(&mut [0; 10]).is_err());
+    assert!(r.is_empty());
+
+    let mut r = slice;
+    let buf = &mut [0; 10];
+    let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+    assert!(r.read_buf_exact(buf.unfilled()).is_err());
+    assert!(r.is_empty());
+    assert_eq!(buf.filled(), b"123456");
+}
+
+#[test]
+fn cursor_read_exact_eof() {
+    let slice = Cursor::new(b"123456");
+
+    let mut r = slice.clone();
+    assert!(r.read_exact(&mut [0; 10]).is_err());
+    assert!(r.is_empty());
+
+    let mut r = slice;
+    let buf = &mut [0; 10];
+    let mut buf = BorrowedBuf::from(buf.as_mut_slice());
+    assert!(r.read_buf_exact(buf.unfilled()).is_err());
+    assert!(r.is_empty());
+    assert_eq!(buf.filled(), b"123456");
+}
+
 #[bench]
 fn bench_take_read(b: &mut test::Bencher) {
     b.iter(|| {
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 27b46b4..949c543 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -435,6 +435,7 @@
 // so include it here even if it's unused.
 #[doc(masked)]
 #[allow(unused_extern_crates)]
+#[cfg(not(all(windows, target_env = "msvc")))]
 extern crate libc;
 
 // We always need an unwinder currently for backtraces
diff --git a/library/std/src/os/hermit/mod.rs b/library/std/src/os/hermit/mod.rs
index 89b1b83..02a4b2c 100644
--- a/library/std/src/os/hermit/mod.rs
+++ b/library/std/src/os/hermit/mod.rs
@@ -2,7 +2,7 @@
 
 #[allow(unused_extern_crates)]
 #[stable(feature = "rust1", since = "1.0.0")]
-pub extern crate hermit_abi as abi;
+pub extern crate hermit_abi;
 
 pub mod ffi;
 pub mod io;
diff --git a/library/std/src/os/raw/tests.rs b/library/std/src/os/raw/tests.rs
index e7bb7d7..f41a22e 100644
--- a/library/std/src/os/raw/tests.rs
+++ b/library/std/src/os/raw/tests.rs
@@ -1,3 +1,5 @@
+#![cfg(not(all(windows, target_env = "msvc")))]
+
 use crate::any::TypeId;
 
 macro_rules! ok {
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index 15ab225..9cca27f 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -199,14 +199,14 @@
 
     /// Append literal text to the command line without any quoting or escaping.
     ///
-    /// This is useful for passing arguments to applications which doesn't follow
+    /// This is useful for passing arguments to applications that don't follow
     /// the standard C run-time escaping rules, such as `cmd.exe /c`.
     ///
-    /// # Bat files
+    /// # Batch files
     ///
-    /// Note the `cmd /c` command line has slightly different escaping rules then bat files
+    /// Note the `cmd /c` command line has slightly different escaping rules than batch files
     /// themselves. If possible, it may be better to write complex arguments to a temporary
-    /// .bat file, with appropriate escaping, and simply run that using:
+    /// `.bat` file, with appropriate escaping, and simply run that using:
     ///
     /// ```no_run
     /// # use std::process::Command;
@@ -217,7 +217,7 @@
     ///
     /// # Example
     ///
-    /// Run a bat script using both trusted and untrusted arguments.
+    /// Run a batch script using both trusted and untrusted arguments.
     ///
     /// ```no_run
     /// #[cfg(windows)]
@@ -241,9 +241,10 @@
     ///     if !user_name.chars().all(|c| c.is_alphanumeric()) {
     ///         return Err(Error::new(ErrorKind::InvalidInput, "invalid user name"));
     ///     }
-    ///     // now we've checked the user name, let's add that too.
-    ///     cmd_args.push(' ');
-    ///     cmd_args.push_str(&format!("--user {user_name}"));
+    ///
+    ///     // now we have validated the user name, let's add that too.
+    ///     cmd_args.push_str(" --user ");
+    ///     cmd_args.push_str(user_name);
     ///
     ///     // call cmd.exe and return the output
     ///     Command::new("cmd.exe")
@@ -287,25 +288,37 @@
     #[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")]
     fn async_pipes(&mut self, always_async: bool) -> &mut process::Command;
 
-    /// Sets a raw attribute on the command, providing extended configuration options for Windows processes.
+    /// Set a raw attribute on the command, providing extended configuration options for Windows
+    /// processes.
     ///
-    /// This method allows you to specify custom attributes for a child process on Windows systems using raw attribute values.
-    /// Raw attributes provide extended configurability for process creation, but their usage can be complex and potentially unsafe.
+    /// This method allows you to specify custom attributes for a child process on Windows systems
+    /// using raw attribute values. Raw attributes provide extended configurability for process
+    /// creation, but their usage can be complex and potentially unsafe.
     ///
-    /// The `attribute` parameter specifies the raw attribute to be set, while the `value` parameter holds the value associated with that attribute.
-    /// Please refer to the [`windows-rs`](https://microsoft.github.io/windows-docs-rs/doc/windows/) documentation or the [`Win32 API documentation`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute) for detailed information about available attributes and their meanings.
+    /// The `attribute` parameter specifies the raw attribute to be set, while the `value`
+    /// parameter holds the value associated with that attribute. Please refer to the
+    /// [`windows-rs` documentation] or the [Win32 API documentation] for detailed information
+    /// about available attributes and their meanings.
+    ///
+    /// [`windows-rs` documentation]: https://microsoft.github.io/windows-docs-rs/doc/windows/
+    /// [Win32 API documentation]: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute
     ///
     /// # Note
     ///
     /// The maximum number of raw attributes is the value of [`u32::MAX`].
-    /// If this limit is exceeded, the call to [`process::Command::spawn`] will return an `Error` indicating that the maximum number of attributes has been exceeded.
+    /// If this limit is exceeded, the call to [`process::Command::spawn`] will return an `Error`
+    /// indicating that the maximum number of attributes has been exceeded.
+    ///
     /// # Safety
     ///
-    /// The usage of raw attributes is potentially unsafe and should be done with caution. Incorrect attribute values or improper configuration can lead to unexpected behavior or errors.
+    /// The usage of raw attributes is potentially unsafe and should be done with caution.
+    /// Incorrect attribute values or improper configuration can lead to unexpected behavior or
+    /// errors.
     ///
     /// # Example
     ///
-    /// The following example demonstrates how to create a child process with a specific parent process ID using a raw attribute.
+    /// The following example demonstrates how to create a child process with a specific parent
+    /// process ID using a raw attribute.
     ///
     /// ```rust
     /// #![feature(windows_process_extensions_raw_attribute)]
@@ -339,7 +352,9 @@
     ///
     /// # Safety Note
     ///
-    /// Remember that improper use of raw attributes can lead to undefined behavior or security vulnerabilities. Always consult the documentation and ensure proper attribute values are used.
+    /// Remember that improper use of raw attributes can lead to undefined behavior or security
+    /// vulnerabilities. Always consult the documentation and ensure proper attribute values are
+    /// used.
     #[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
     unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
         &mut self,
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 79d800f..f835b69 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -3323,7 +3323,7 @@
 ///
 /// # Examples
 ///
-/// ## Posix paths
+/// ## POSIX paths
 ///
 /// ```
 /// # #[cfg(unix)]
@@ -3369,9 +3369,12 @@
 /// ```
 ///
 /// For verbatim paths this will simply return the path as given. For other
-/// paths this is currently equivalent to calling [`GetFullPathNameW`][windows-path]
-/// This may change in the future.
+/// paths this is currently equivalent to calling
+/// [`GetFullPathNameW`][windows-path].
 ///
+/// Note that this [may change in the future][changes].
+///
+/// [changes]: io#platform-specific-behavior
 /// [posix-semantics]: https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
 /// [windows-path]: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew
 #[stable(feature = "absolute_path", since = "1.79.0")]
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index d184822..c926c89 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -90,8 +90,8 @@
 //!
 //! # Windows argument splitting
 //!
-//! On Unix systems arguments are passed to a new process as an array of strings
-//! but on Windows arguments are passed as a single commandline string and it's
+//! On Unix systems arguments are passed to a new process as an array of strings,
+//! but on Windows arguments are passed as a single commandline string and it is
 //! up to the child process to parse it into an array. Therefore the parent and
 //! child processes must agree on how the commandline string is encoded.
 //!
@@ -107,26 +107,26 @@
 //! * Use [`raw_arg`] to build a custom commandline. This bypasses the escaping
 //!   rules used by [`arg`] so should be used with due caution.
 //!
-//! `cmd.exe` and `.bat` use non-standard argument parsing and are especially
+//! `cmd.exe` and `.bat` files use non-standard argument parsing and are especially
 //! vulnerable to malicious input as they may be used to run arbitrary shell
 //! commands. Untrusted arguments should be restricted as much as possible.
 //! For examples on handling this see [`raw_arg`].
 //!
-//! ### Bat file special handling
+//! ### Batch file special handling
 //!
 //! On Windows, `Command` uses the Windows API function [`CreateProcessW`] to
-//! spawn new processes. An undocumented feature of this function is that,
+//! spawn new processes. An undocumented feature of this function is that
 //! when given a `.bat` file as the application to run, it will automatically
-//! convert that into running `cmd.exe /c` with the bat file as the next argument.
+//! convert that into running `cmd.exe /c` with the batch file as the next argument.
 //!
 //! For historical reasons Rust currently preserves this behaviour when using
 //! [`Command::new`], and escapes the arguments according to `cmd.exe` rules.
 //! Due to the complexity of `cmd.exe` argument handling, it might not be
-//! possible to safely escape some special chars, and using them will result
+//! possible to safely escape some special characters, and using them will result
 //! in an error being returned at process spawn. The set of unescapeable
-//! special chars might change between releases.
+//! special characters might change between releases.
 //!
-//! Also note that running `.bat` scripts in this way may be removed in the
+//! Also note that running batch scripts in this way may be removed in the
 //! future and so should not be relied upon.
 //!
 //! [`spawn`]: Command::spawn
@@ -659,16 +659,19 @@
     ///
     /// Note that the argument is not passed through a shell, but given
     /// literally to the program. This means that shell syntax like quotes,
-    /// escaped characters, word splitting, glob patterns, variable substitution, etc.
-    /// have no effect.
+    /// escaped characters, word splitting, glob patterns, variable substitution,
+    /// etc. have no effect.
     ///
     /// <div class="warning">
     ///
-    /// On Windows use caution with untrusted inputs. Most applications use the
-    /// standard convention for decoding arguments passed to them. These are safe to use with `arg`.
-    /// However some applications, such as `cmd.exe` and `.bat` files, use a non-standard way of decoding arguments
-    /// and are therefore vulnerable to malicious input.
-    /// In the case of `cmd.exe` this is especially important because a malicious argument can potentially run arbitrary shell commands.
+    /// On Windows, use caution with untrusted inputs. Most applications use the
+    /// standard convention for decoding arguments passed to them. These are safe to
+    /// use with `arg`. However, some applications such as `cmd.exe` and `.bat` files
+    /// use a non-standard way of decoding arguments. They are therefore vulnerable
+    /// to malicious input.
+    ///
+    /// In the case of `cmd.exe` this is especially important because a malicious
+    /// argument can potentially run arbitrary shell commands.
     ///
     /// See [Windows argument splitting][windows-args] for more details
     /// or [`raw_arg`] for manually implementing non-standard argument encoding.
@@ -710,11 +713,14 @@
     ///
     /// <div class="warning">
     ///
-    /// On Windows use caution with untrusted inputs. Most applications use the
-    /// standard convention for decoding arguments passed to them. These are safe to use with `args`.
-    /// However some applications, such as `cmd.exe` and `.bat` files, use a non-standard way of decoding arguments
-    /// and are therefore vulnerable to malicious input.
-    /// In the case of `cmd.exe` this is especially important because a malicious argument can potentially run arbitrary shell commands.
+    /// On Windows, use caution with untrusted inputs. Most applications use the
+    /// standard convention for decoding arguments passed to them. These are safe to
+    /// use with `arg`. However, some applications such as `cmd.exe` and `.bat` files
+    /// use a non-standard way of decoding arguments. They are therefore vulnerable
+    /// to malicious input.
+    ///
+    /// In the case of `cmd.exe` this is especially important because a malicious
+    /// argument can potentially run arbitrary shell commands.
     ///
     /// See [Windows argument splitting][windows-args] for more details
     /// or [`raw_arg`] for manually implementing non-standard argument encoding.
diff --git a/library/std/src/sys/pal/hermit/alloc.rs b/library/std/src/sys/pal/hermit/alloc.rs
index de55098..2cd0db9 100644
--- a/library/std/src/sys/pal/hermit/alloc.rs
+++ b/library/std/src/sys/pal/hermit/alloc.rs
@@ -1,4 +1,4 @@
-use super::abi;
+use super::hermit_abi;
 use crate::alloc::{GlobalAlloc, Layout, System};
 use crate::ptr;
 
@@ -6,11 +6,11 @@
 unsafe impl GlobalAlloc for System {
     #[inline]
     unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
-        abi::malloc(layout.size(), layout.align())
+        hermit_abi::malloc(layout.size(), layout.align())
     }
 
     unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
-        let addr = abi::malloc(layout.size(), layout.align());
+        let addr = hermit_abi::malloc(layout.size(), layout.align());
 
         if !addr.is_null() {
             ptr::write_bytes(addr, 0x00, layout.size());
@@ -21,11 +21,11 @@
 
     #[inline]
     unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
-        abi::free(ptr, layout.size(), layout.align())
+        hermit_abi::free(ptr, layout.size(), layout.align())
     }
 
     #[inline]
     unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
-        abi::realloc(ptr, layout.size(), layout.align(), new_size)
+        hermit_abi::realloc(ptr, layout.size(), layout.align(), new_size)
     }
 }
diff --git a/library/std/src/sys/pal/hermit/fd.rs b/library/std/src/sys/pal/hermit/fd.rs
index 962577b..d7dab08 100644
--- a/library/std/src/sys/pal/hermit/fd.rs
+++ b/library/std/src/sys/pal/hermit/fd.rs
@@ -1,6 +1,6 @@
 #![unstable(reason = "not public", issue = "none", feature = "fd")]
 
-use super::abi;
+use super::hermit_abi;
 use crate::io::{self, Read};
 use crate::os::hermit::io::{FromRawFd, OwnedFd, RawFd};
 use crate::sys::cvt;
@@ -16,7 +16,8 @@
 
 impl FileDesc {
     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
-        let result = cvt(unsafe { abi::read(self.fd.as_raw_fd(), buf.as_mut_ptr(), buf.len()) })?;
+        let result =
+            cvt(unsafe { hermit_abi::read(self.fd.as_raw_fd(), buf.as_mut_ptr(), buf.len()) })?;
         Ok(result as usize)
     }
 
@@ -26,7 +27,8 @@
     }
 
     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
-        let result = cvt(unsafe { abi::write(self.fd.as_raw_fd(), buf.as_ptr(), buf.len()) })?;
+        let result =
+            cvt(unsafe { hermit_abi::write(self.fd.as_raw_fd(), buf.as_ptr(), buf.len()) })?;
         Ok(result as usize)
     }
 
@@ -49,8 +51,8 @@
         unsupported()
     }
 
-    pub fn fstat(&self, stat: *mut abi::stat) -> io::Result<()> {
-        cvt(unsafe { abi::fstat(self.fd.as_raw_fd(), stat) })?;
+    pub fn fstat(&self, stat: *mut hermit_abi::stat) -> io::Result<()> {
+        cvt(unsafe { hermit_abi::fstat(self.fd.as_raw_fd(), stat) })?;
         Ok(())
     }
 }
diff --git a/library/std/src/sys/pal/hermit/fs.rs b/library/std/src/sys/pal/hermit/fs.rs
index 6519cc2..a4a16e6 100644
--- a/library/std/src/sys/pal/hermit/fs.rs
+++ b/library/std/src/sys/pal/hermit/fs.rs
@@ -1,8 +1,8 @@
-use super::abi::{
+use super::fd::FileDesc;
+use super::hermit_abi::{
     self, dirent64, stat as stat_struct, DT_DIR, DT_LNK, DT_REG, DT_UNKNOWN, O_APPEND, O_CREAT,
     O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG,
 };
-use super::fd::FileDesc;
 use crate::ffi::{CStr, OsStr, OsString};
 use crate::fmt;
 use crate::io::{self, Error, ErrorKind};
@@ -47,7 +47,7 @@
 
 pub struct ReadDir {
     inner: Arc<InnerReadDir>,
-    pos: i64,
+    pos: usize,
 }
 
 impl ReadDir {
@@ -197,38 +197,31 @@
 
     fn next(&mut self) -> Option<io::Result<DirEntry>> {
         let mut counter: usize = 0;
-        let mut offset: i64 = 0;
+        let mut offset: usize = 0;
 
         // loop over all directory entries and search the entry for the current position
         loop {
             // leave function, if the loop reaches the of the buffer (with all entries)
-            if offset >= self.inner.dir.len().try_into().unwrap() {
+            if offset >= self.inner.dir.len() {
                 return None;
             }
 
-            let dir = unsafe {
-                &*(self.inner.dir.as_ptr().offset(offset.try_into().unwrap()) as *const dirent64)
-            };
+            let dir = unsafe { &*(self.inner.dir.as_ptr().add(offset) as *const dirent64) };
 
-            if counter == self.pos.try_into().unwrap() {
+            if counter == self.pos {
                 self.pos += 1;
 
                 // After dirent64, the file name is stored. d_reclen represents the length of the dirent64
                 // plus the length of the file name. Consequently, file name has a size of d_reclen minus
                 // the size of dirent64. The file name is always a C string and terminated by `\0`.
                 // Consequently, we are able to ignore the last byte.
-                let name_bytes = unsafe {
-                    core::slice::from_raw_parts(
-                        &dir.d_name as *const _ as *const u8,
-                        dir.d_reclen as usize - core::mem::size_of::<dirent64>() - 1,
-                    )
-                    .to_vec()
-                };
+                let name_bytes =
+                    unsafe { CStr::from_ptr(&dir.d_name as *const _ as *const i8).to_bytes() };
                 let entry = DirEntry {
                     root: self.inner.root.clone(),
                     ino: dir.d_ino,
                     type_: dir.d_type as u32,
-                    name: OsString::from_vec(name_bytes),
+                    name: OsString::from_vec(name_bytes.to_vec()),
                 };
 
                 return Some(Ok(entry));
@@ -237,7 +230,7 @@
             counter += 1;
 
             // move to the next dirent64, which is directly stored after the previous one
-            offset = offset + dir.d_off;
+            offset = offset + usize::from(dir.d_reclen);
         }
     }
 }
@@ -365,7 +358,7 @@
             mode = 0;
         }
 
-        let fd = unsafe { cvt(abi::open(path.as_ptr(), flags, mode))? };
+        let fd = unsafe { cvt(hermit_abi::open(path.as_ptr(), flags, mode))? };
         Ok(File(unsafe { FileDesc::from_raw_fd(fd as i32) }))
     }
 
@@ -446,7 +439,7 @@
 
     pub fn mkdir(&self, path: &Path) -> io::Result<()> {
         run_path_with_cstr(path, &|path| {
-            cvt(unsafe { abi::mkdir(path.as_ptr(), self.mode) }).map(|_| ())
+            cvt(unsafe { hermit_abi::mkdir(path.as_ptr(), self.mode) }).map(|_| ())
         })
     }
 
@@ -508,7 +501,8 @@
 }
 
 pub fn readdir(path: &Path) -> io::Result<ReadDir> {
-    let fd_raw = run_path_with_cstr(path, &|path| cvt(unsafe { abi::opendir(path.as_ptr()) }))?;
+    let fd_raw =
+        run_path_with_cstr(path, &|path| cvt(unsafe { hermit_abi::opendir(path.as_ptr()) }))?;
     let fd = unsafe { FileDesc::from_raw_fd(fd_raw as i32) };
     let root = path.to_path_buf();
 
@@ -519,8 +513,9 @@
         // reserve memory to receive all directory entries
         vec.resize(sz, 0);
 
-        let readlen =
-            unsafe { abi::getdents64(fd.as_raw_fd(), vec.as_mut_ptr() as *mut dirent64, sz) };
+        let readlen = unsafe {
+            hermit_abi::getdents64(fd.as_raw_fd(), vec.as_mut_ptr() as *mut dirent64, sz)
+        };
         if readlen > 0 {
             // shrink down to the minimal size
             vec.resize(readlen.try_into().unwrap(), 0);
@@ -529,7 +524,7 @@
 
         // if the buffer is too small, getdents64 returns EINVAL
         // otherwise, getdents64 returns an error number
-        if readlen != (-abi::errno::EINVAL).into() {
+        if readlen != (-hermit_abi::errno::EINVAL).into() {
             return Err(Error::from_raw_os_error(readlen.try_into().unwrap()));
         }
 
@@ -547,7 +542,7 @@
 }
 
 pub fn unlink(path: &Path) -> io::Result<()> {
-    run_path_with_cstr(path, &|path| cvt(unsafe { abi::unlink(path.as_ptr()) }).map(|_| ()))
+    run_path_with_cstr(path, &|path| cvt(unsafe { hermit_abi::unlink(path.as_ptr()) }).map(|_| ()))
 }
 
 pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
@@ -559,7 +554,7 @@
 }
 
 pub fn rmdir(path: &Path) -> io::Result<()> {
-    run_path_with_cstr(path, &|path| cvt(unsafe { abi::rmdir(path.as_ptr()) }).map(|_| ()))
+    run_path_with_cstr(path, &|path| cvt(unsafe { hermit_abi::rmdir(path.as_ptr()) }).map(|_| ()))
 }
 
 pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
@@ -581,7 +576,7 @@
 pub fn stat(path: &Path) -> io::Result<FileAttr> {
     run_path_with_cstr(path, &|path| {
         let mut stat_val: stat_struct = unsafe { mem::zeroed() };
-        cvt(unsafe { abi::stat(path.as_ptr(), &mut stat_val) })?;
+        cvt(unsafe { hermit_abi::stat(path.as_ptr(), &mut stat_val) })?;
         Ok(FileAttr::from_stat(stat_val))
     })
 }
@@ -589,7 +584,7 @@
 pub fn lstat(path: &Path) -> io::Result<FileAttr> {
     run_path_with_cstr(path, &|path| {
         let mut stat_val: stat_struct = unsafe { mem::zeroed() };
-        cvt(unsafe { abi::lstat(path.as_ptr(), &mut stat_val) })?;
+        cvt(unsafe { hermit_abi::lstat(path.as_ptr(), &mut stat_val) })?;
         Ok(FileAttr::from_stat(stat_val))
     })
 }
diff --git a/library/std/src/sys/pal/hermit/futex.rs b/library/std/src/sys/pal/hermit/futex.rs
index 427d8ff..571b288 100644
--- a/library/std/src/sys/pal/hermit/futex.rs
+++ b/library/std/src/sys/pal/hermit/futex.rs
@@ -1,4 +1,4 @@
-use super::abi;
+use super::hermit_abi;
 use crate::ptr::null;
 use crate::sync::atomic::AtomicU32;
 use crate::time::Duration;
@@ -8,32 +8,32 @@
     //
     // Overflows are rounded up to an infinite timeout (None).
     let timespec = timeout.and_then(|dur| {
-        Some(abi::timespec {
+        Some(hermit_abi::timespec {
             tv_sec: dur.as_secs().try_into().ok()?,
             tv_nsec: dur.subsec_nanos().into(),
         })
     });
 
     let r = unsafe {
-        abi::futex_wait(
+        hermit_abi::futex_wait(
             futex.as_ptr(),
             expected,
-            timespec.as_ref().map_or(null(), |t| t as *const abi::timespec),
-            abi::FUTEX_RELATIVE_TIMEOUT,
+            timespec.as_ref().map_or(null(), |t| t as *const hermit_abi::timespec),
+            hermit_abi::FUTEX_RELATIVE_TIMEOUT,
         )
     };
 
-    r != -abi::errno::ETIMEDOUT
+    r != -hermit_abi::errno::ETIMEDOUT
 }
 
 #[inline]
 pub fn futex_wake(futex: &AtomicU32) -> bool {
-    unsafe { abi::futex_wake(futex.as_ptr(), 1) > 0 }
+    unsafe { hermit_abi::futex_wake(futex.as_ptr(), 1) > 0 }
 }
 
 #[inline]
 pub fn futex_wake_all(futex: &AtomicU32) {
     unsafe {
-        abi::futex_wake(futex.as_ptr(), i32::MAX);
+        hermit_abi::futex_wake(futex.as_ptr(), i32::MAX);
     }
 }
diff --git a/library/std/src/sys/pal/hermit/mod.rs b/library/std/src/sys/pal/hermit/mod.rs
index 9109355..a64323a 100644
--- a/library/std/src/sys/pal/hermit/mod.rs
+++ b/library/std/src/sys/pal/hermit/mod.rs
@@ -39,7 +39,7 @@
 pub mod time;
 
 use crate::io::ErrorKind;
-use crate::os::hermit::abi;
+use crate::os::hermit::hermit_abi;
 
 pub fn unsupported<T>() -> crate::io::Result<T> {
     Err(unsupported_err())
@@ -54,7 +54,7 @@
 
 pub fn abort_internal() -> ! {
     unsafe {
-        abi::abort();
+        hermit_abi::abort();
     }
 }
 
@@ -62,7 +62,7 @@
     let mut buf = [0; 16];
     let mut slice = &mut buf[..];
     while !slice.is_empty() {
-        let res = cvt(unsafe { abi::read_entropy(slice.as_mut_ptr(), slice.len(), 0) })
+        let res = cvt(unsafe { hermit_abi::read_entropy(slice.as_mut_ptr(), slice.len(), 0) })
             .expect("failed to generate random hashmap keys");
         slice = &mut slice[res as usize..];
     }
@@ -109,31 +109,31 @@
     let result = main(argc as isize, argv);
 
     run_dtors();
-    abi::exit(result);
+    hermit_abi::exit(result);
 }
 
 #[inline]
 pub(crate) fn is_interrupted(errno: i32) -> bool {
-    errno == abi::errno::EINTR
+    errno == hermit_abi::errno::EINTR
 }
 
 pub fn decode_error_kind(errno: i32) -> ErrorKind {
     match errno {
-        abi::errno::EACCES => ErrorKind::PermissionDenied,
-        abi::errno::EADDRINUSE => ErrorKind::AddrInUse,
-        abi::errno::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
-        abi::errno::EAGAIN => ErrorKind::WouldBlock,
-        abi::errno::ECONNABORTED => ErrorKind::ConnectionAborted,
-        abi::errno::ECONNREFUSED => ErrorKind::ConnectionRefused,
-        abi::errno::ECONNRESET => ErrorKind::ConnectionReset,
-        abi::errno::EEXIST => ErrorKind::AlreadyExists,
-        abi::errno::EINTR => ErrorKind::Interrupted,
-        abi::errno::EINVAL => ErrorKind::InvalidInput,
-        abi::errno::ENOENT => ErrorKind::NotFound,
-        abi::errno::ENOTCONN => ErrorKind::NotConnected,
-        abi::errno::EPERM => ErrorKind::PermissionDenied,
-        abi::errno::EPIPE => ErrorKind::BrokenPipe,
-        abi::errno::ETIMEDOUT => ErrorKind::TimedOut,
+        hermit_abi::errno::EACCES => ErrorKind::PermissionDenied,
+        hermit_abi::errno::EADDRINUSE => ErrorKind::AddrInUse,
+        hermit_abi::errno::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
+        hermit_abi::errno::EAGAIN => ErrorKind::WouldBlock,
+        hermit_abi::errno::ECONNABORTED => ErrorKind::ConnectionAborted,
+        hermit_abi::errno::ECONNREFUSED => ErrorKind::ConnectionRefused,
+        hermit_abi::errno::ECONNRESET => ErrorKind::ConnectionReset,
+        hermit_abi::errno::EEXIST => ErrorKind::AlreadyExists,
+        hermit_abi::errno::EINTR => ErrorKind::Interrupted,
+        hermit_abi::errno::EINVAL => ErrorKind::InvalidInput,
+        hermit_abi::errno::ENOENT => ErrorKind::NotFound,
+        hermit_abi::errno::ENOTCONN => ErrorKind::NotConnected,
+        hermit_abi::errno::EPERM => ErrorKind::PermissionDenied,
+        hermit_abi::errno::EPIPE => ErrorKind::BrokenPipe,
+        hermit_abi::errno::ETIMEDOUT => ErrorKind::TimedOut,
         _ => ErrorKind::Uncategorized,
     }
 }
diff --git a/library/std/src/sys/pal/hermit/net.rs b/library/std/src/sys/pal/hermit/net.rs
index 23ac71c..00dbca8 100644
--- a/library/std/src/sys/pal/hermit/net.rs
+++ b/library/std/src/sys/pal/hermit/net.rs
@@ -175,23 +175,12 @@
     }
 
     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
-        let mut size: isize = 0;
-
-        for i in bufs.iter_mut() {
-            let ret: isize =
-                cvt(unsafe { netc::read(self.0.as_raw_fd(), i.as_mut_ptr(), i.len()) })?;
-
-            if ret != 0 {
-                size += ret;
-            }
-        }
-
-        Ok(size.try_into().unwrap())
+        crate::io::default_read_vectored(|b| self.read(b), bufs)
     }
 
     #[inline]
     pub fn is_read_vectored(&self) -> bool {
-        true
+        false
     }
 
     fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<(usize, SocketAddr)> {
@@ -225,17 +214,11 @@
     }
 
     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
-        let mut size: isize = 0;
-
-        for i in bufs.iter() {
-            size += cvt(unsafe { netc::write(self.0.as_raw_fd(), i.as_ptr(), i.len()) })?;
-        }
-
-        Ok(size.try_into().unwrap())
+        crate::io::default_write_vectored(|b| self.write(b), bufs)
     }
 
     pub fn is_write_vectored(&self) -> bool {
-        true
+        false
     }
 
     pub fn set_timeout(&self, dur: Option<Duration>, kind: i32) -> io::Result<()> {
diff --git a/library/std/src/sys/pal/hermit/os.rs b/library/std/src/sys/pal/hermit/os.rs
index 1f9affb..cc67812 100644
--- a/library/std/src/sys/pal/hermit/os.rs
+++ b/library/std/src/sys/pal/hermit/os.rs
@@ -1,4 +1,4 @@
-use super::abi;
+use super::hermit_abi;
 use crate::collections::HashMap;
 use crate::error::Error as StdError;
 use crate::ffi::{CStr, OsStr, OsString};
@@ -14,11 +14,11 @@
 use core::slice::memchr;
 
 pub fn errno() -> i32 {
-    unsafe { abi::get_errno() }
+    unsafe { hermit_abi::get_errno() }
 }
 
 pub fn error_string(errno: i32) -> String {
-    abi::error_string(errno).to_string()
+    hermit_abi::error_string(errno).to_string()
 }
 
 pub fn getcwd() -> io::Result<PathBuf> {
@@ -197,10 +197,10 @@
 
 pub fn exit(code: i32) -> ! {
     unsafe {
-        abi::exit(code);
+        hermit_abi::exit(code);
     }
 }
 
 pub fn getpid() -> u32 {
-    unsafe { abi::getpid() }
+    unsafe { hermit_abi::getpid() }
 }
diff --git a/library/std/src/sys/pal/hermit/stdio.rs b/library/std/src/sys/pal/hermit/stdio.rs
index ac54385..777c57b 100644
--- a/library/std/src/sys/pal/hermit/stdio.rs
+++ b/library/std/src/sys/pal/hermit/stdio.rs
@@ -1,4 +1,4 @@
-use super::abi;
+use super::hermit_abi;
 use crate::io;
 use crate::io::{IoSlice, IoSliceMut};
 
@@ -37,7 +37,7 @@
     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         let len;
 
-        unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
+        unsafe { len = hermit_abi::write(1, data.as_ptr() as *const u8, data.len()) }
 
         if len < 0 {
             Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print"))
@@ -49,7 +49,7 @@
     fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
         let len;
 
-        unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) }
+        unsafe { len = hermit_abi::write(1, data.as_ptr() as *const u8, data.len()) }
 
         if len < 0 {
             Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stdout is not able to print"))
@@ -78,7 +78,7 @@
     fn write(&mut self, data: &[u8]) -> io::Result<usize> {
         let len;
 
-        unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
+        unsafe { len = hermit_abi::write(2, data.as_ptr() as *const u8, data.len()) }
 
         if len < 0 {
             Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print"))
@@ -90,7 +90,7 @@
     fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> {
         let len;
 
-        unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) }
+        unsafe { len = hermit_abi::write(2, data.as_ptr() as *const u8, data.len()) }
 
         if len < 0 {
             Err(io::const_io_error!(io::ErrorKind::Uncategorized, "Stderr is not able to print"))
diff --git a/library/std/src/sys/pal/hermit/thread.rs b/library/std/src/sys/pal/hermit/thread.rs
index 4fe6b12..b336dcd 100644
--- a/library/std/src/sys/pal/hermit/thread.rs
+++ b/library/std/src/sys/pal/hermit/thread.rs
@@ -1,6 +1,6 @@
 #![allow(dead_code)]
 
-use super::abi;
+use super::hermit_abi;
 use super::thread_local_dtor::run_dtors;
 use crate::ffi::CStr;
 use crate::io;
@@ -9,7 +9,7 @@
 use crate::ptr;
 use crate::time::Duration;
 
-pub type Tid = abi::Tid;
+pub type Tid = hermit_abi::Tid;
 
 pub struct Thread {
     tid: Tid,
@@ -27,10 +27,10 @@
         core_id: isize,
     ) -> io::Result<Thread> {
         let p = Box::into_raw(Box::new(p));
-        let tid = abi::spawn2(
+        let tid = hermit_abi::spawn2(
             thread_start,
             p.expose_provenance(),
-            abi::Priority::into(abi::NORMAL_PRIO),
+            hermit_abi::Priority::into(hermit_abi::NORMAL_PRIO),
             stack,
             core_id,
         );
@@ -62,7 +62,7 @@
     #[inline]
     pub fn yield_now() {
         unsafe {
-            abi::yield_now();
+            hermit_abi::yield_now();
         }
     }
 
@@ -74,13 +74,13 @@
     #[inline]
     pub fn sleep(dur: Duration) {
         unsafe {
-            abi::usleep(dur.as_micros() as u64);
+            hermit_abi::usleep(dur.as_micros() as u64);
         }
     }
 
     pub fn join(self) {
         unsafe {
-            let _ = abi::join(self.tid);
+            let _ = hermit_abi::join(self.tid);
         }
     }
 
@@ -98,5 +98,5 @@
 }
 
 pub fn available_parallelism() -> io::Result<NonZero<usize>> {
-    unsafe { Ok(NonZero::new_unchecked(abi::get_processor_count())) }
+    unsafe { Ok(NonZero::new_unchecked(hermit_abi::get_processor_count())) }
 }
diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs
index d6f9e4c..2bf2446 100644
--- a/library/std/src/sys/pal/hermit/time.rs
+++ b/library/std/src/sys/pal/hermit/time.rs
@@ -1,8 +1,6 @@
 #![allow(dead_code)]
 
-use super::abi;
-use super::abi::timespec;
-use super::abi::{CLOCK_MONOTONIC, CLOCK_REALTIME, NSEC_PER_SEC};
+use super::hermit_abi::{self, timespec, CLOCK_MONOTONIC, CLOCK_REALTIME, NSEC_PER_SEC};
 use crate::cmp::Ordering;
 use crate::ops::{Add, AddAssign, Sub, SubAssign};
 use crate::time::Duration;
@@ -106,7 +104,8 @@
 impl Instant {
     pub fn now() -> Instant {
         let mut time: Timespec = Timespec::zero();
-        let _ = unsafe { abi::clock_gettime(CLOCK_MONOTONIC, core::ptr::addr_of_mut!(time.t)) };
+        let _ =
+            unsafe { hermit_abi::clock_gettime(CLOCK_MONOTONIC, core::ptr::addr_of_mut!(time.t)) };
 
         Instant(time)
     }
@@ -207,7 +206,8 @@
 
     pub fn now() -> SystemTime {
         let mut time: Timespec = Timespec::zero();
-        let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, core::ptr::addr_of_mut!(time.t)) };
+        let _ =
+            unsafe { hermit_abi::clock_gettime(CLOCK_REALTIME, core::ptr::addr_of_mut!(time.t)) };
 
         SystemTime(time)
     }
diff --git a/library/std/src/sys/pal/unix/alloc.rs b/library/std/src/sys/pal/unix/alloc.rs
index 9938c0b..2f908e3 100644
--- a/library/std/src/sys/pal/unix/alloc.rs
+++ b/library/std/src/sys/pal/unix/alloc.rs
@@ -59,51 +59,29 @@
 }
 
 cfg_if::cfg_if! {
+    // We use posix_memalign wherever possible, but not all targets have that function.
     if #[cfg(any(
-        target_os = "android",
-        target_os = "illumos",
         target_os = "redox",
-        target_os = "solaris",
         target_os = "espidf",
         target_os = "horizon",
         target_os = "vita",
     ))] {
         #[inline]
         unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
-            // On android we currently target API level 9 which unfortunately
-            // doesn't have the `posix_memalign` API used below. Instead we use
-            // `memalign`, but this unfortunately has the property on some systems
-            // where the memory returned cannot be deallocated by `free`!
-            //
-            // Upon closer inspection, however, this appears to work just fine with
-            // Android, so for this platform we should be fine to call `memalign`
-            // (which is present in API level 9). Some helpful references could
-            // possibly be chromium using memalign [1], attempts at documenting that
-            // memalign + free is ok [2] [3], or the current source of chromium
-            // which still uses memalign on android [4].
-            //
-            // [1]: https://codereview.chromium.org/10796020/
-            // [2]: https://code.google.com/p/android/issues/detail?id=35391
-            // [3]: https://bugs.chromium.org/p/chromium/issues/detail?id=138579
-            // [4]: https://chromium.googlesource.com/chromium/src/base/+/master/
-            //                                       /memory/aligned_memory.cc
             libc::memalign(layout.align(), layout.size()) as *mut u8
         }
-    } else if #[cfg(target_os = "wasi")] {
-        #[inline]
-        unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
-            // C11 aligned_alloc requires that the size be a multiple of the alignment.
-            // Layout already checks that the size rounded up doesn't overflow isize::MAX.
-            let align = layout.align();
-            let size = layout.size().next_multiple_of(align);
-            libc::aligned_alloc(align, size) as *mut u8
-        }
     } else {
         #[inline]
         unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
             let mut out = ptr::null_mut();
-            // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`.
-            // Since these are all powers of 2, we can just use max.
+            // We prefer posix_memalign over aligned_malloc since with aligned_malloc,
+            // implementations are making almost arbitrary choices for which alignments are
+            // "supported", making it hard to use. For instance, some implementations require the
+            // size to be a multiple of the alignment (wasi emmalloc), while others require the
+            // alignment to be at least the pointer size (Illumos, macOS) -- which may or may not be
+            // standards-compliant, but that does not help us.
+            // posix_memalign only has one, clear requirement: that the alignment be a multiple of
+            // `sizeof(void*)`. Since these are all powers of 2, we can just use max.
             let align = layout.align().max(crate::mem::size_of::<usize>());
             let ret = libc::posix_memalign(&mut out, align, layout.size());
             if ret != 0 { ptr::null_mut() } else { out as *mut u8 }
diff --git a/library/std/src/sys/pal/unix/args.rs b/library/std/src/sys/pal/unix/args.rs
index 2a3298e..db2ec73 100644
--- a/library/std/src/sys/pal/unix/args.rs
+++ b/library/std/src/sys/pal/unix/args.rs
@@ -5,8 +5,9 @@
 
 #![allow(dead_code)] // runtime init functions not used during testing
 
-use crate::ffi::OsString;
+use crate::ffi::{CStr, OsString};
 use crate::fmt;
+use crate::os::unix::ffi::OsStringExt;
 use crate::vec;
 
 /// One-time global initialization.
@@ -16,7 +17,46 @@
 
 /// Returns the command line arguments
 pub fn args() -> Args {
-    imp::args()
+    let (argc, argv) = imp::argc_argv();
+
+    let mut vec = Vec::with_capacity(argc as usize);
+
+    for i in 0..argc {
+        // SAFETY: `argv` is non-null if `argc` is positive, and it is
+        // guaranteed to be at least as long as `argc`, so reading from it
+        // should be safe.
+        let ptr = unsafe { argv.offset(i).read() };
+
+        // Some C commandline parsers (e.g. GLib and Qt) are replacing already
+        // handled arguments in `argv` with `NULL` and move them to the end.
+        //
+        // Since they can't directly ensure updates to `argc` as well, this
+        // means that `argc` might be bigger than the actual number of
+        // non-`NULL` pointers in `argv` at this point.
+        //
+        // To handle this we simply stop iterating at the first `NULL`
+        // argument. `argv` is also guaranteed to be `NULL`-terminated so any
+        // non-`NULL` arguments after the first `NULL` can safely be ignored.
+        if ptr.is_null() {
+            // NOTE: On Apple platforms, `-[NSProcessInfo arguments]` does not
+            // stop iterating here, but instead `continue`, always iterating
+            // up until it reached `argc`.
+            //
+            // This difference will only matter in very specific circumstances
+            // where `argc`/`argv` have been modified, but in unexpected ways,
+            // so it likely doesn't really matter which option we choose.
+            // See the following PR for further discussion:
+            // <https://github.com/rust-lang/rust/pull/125225>
+            break;
+        }
+
+        // SAFETY: Just checked that the pointer is not NULL, and arguments
+        // are otherwise guaranteed to be valid C strings.
+        let cstr = unsafe { CStr::from_ptr(ptr) };
+        vec.push(OsStringExt::from_vec(cstr.to_bytes().to_vec()));
+    }
+
+    Args { iter: vec.into_iter() }
 }
 
 pub struct Args {
@@ -75,9 +115,7 @@
     target_os = "hurd",
 ))]
 mod imp {
-    use super::Args;
-    use crate::ffi::{CStr, OsString};
-    use crate::os::unix::prelude::*;
+    use crate::ffi::c_char;
     use crate::ptr;
     use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering};
 
@@ -126,162 +164,78 @@
         init_wrapper
     };
 
-    pub fn args() -> Args {
-        Args { iter: clone().into_iter() }
-    }
+    pub fn argc_argv() -> (isize, *const *const c_char) {
+        // Load ARGC and ARGV, which hold the unmodified system-provided
+        // argc/argv, so we can read the pointed-to memory without atomics or
+        // synchronization.
+        //
+        // If either ARGC or ARGV is still zero or null, then either there
+        // really are no arguments, or someone is asking for `args()` before
+        // initialization has completed, and we return an empty list.
+        let argv = ARGV.load(Ordering::Relaxed);
+        let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
 
-    fn clone() -> Vec<OsString> {
-        unsafe {
-            // Load ARGC and ARGV, which hold the unmodified system-provided
-            // argc/argv, so we can read the pointed-to memory without atomics
-            // or synchronization.
-            //
-            // If either ARGC or ARGV is still zero or null, then either there
-            // really are no arguments, or someone is asking for `args()`
-            // before initialization has completed, and we return an empty
-            // list.
-            let argv = ARGV.load(Ordering::Relaxed);
-            let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
-            let mut args = Vec::with_capacity(argc as usize);
-            for i in 0..argc {
-                let ptr = *argv.offset(i) as *const libc::c_char;
-
-                // Some C commandline parsers (e.g. GLib and Qt) are replacing already
-                // handled arguments in `argv` with `NULL` and move them to the end. That
-                // means that `argc` might be bigger than the actual number of non-`NULL`
-                // pointers in `argv` at this point.
-                //
-                // To handle this we simply stop iterating at the first `NULL` argument.
-                //
-                // `argv` is also guaranteed to be `NULL`-terminated so any non-`NULL` arguments
-                // after the first `NULL` can safely be ignored.
-                if ptr.is_null() {
-                    break;
-                }
-
-                let cstr = CStr::from_ptr(ptr);
-                args.push(OsStringExt::from_vec(cstr.to_bytes().to_vec()));
-            }
-
-            args
-        }
+        // Cast from `*mut *const u8` to `*const *const c_char`
+        (argc, argv.cast())
     }
 }
 
+// Use `_NSGetArgc` and `_NSGetArgv` on Apple platforms.
+//
+// Even though these have underscores in their names, they've been available
+// since since the first versions of both macOS and iOS, and are declared in
+// the header `crt_externs.h`.
+//
+// NOTE: This header was added to the iOS 13.0 SDK, which has been the source
+// of a great deal of confusion in the past about the availability of these
+// APIs.
+//
+// NOTE(madsmtm): This has not strictly been verified to not cause App Store
+// rejections; if this is found to be the case, the previous implementation
+// of this used `[[NSProcessInfo processInfo] arguments]`.
 #[cfg(target_vendor = "apple")]
 mod imp {
-    use super::Args;
-    use crate::ffi::CStr;
+    use crate::ffi::{c_char, c_int};
 
-    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
-
-    #[cfg(target_os = "macos")]
-    pub fn args() -> Args {
-        use crate::os::unix::prelude::*;
-        extern "C" {
-            // These functions are in crt_externs.h.
-            fn _NSGetArgc() -> *mut libc::c_int;
-            fn _NSGetArgv() -> *mut *mut *mut libc::c_char;
-        }
-
-        let vec = unsafe {
-            let (argc, argv) =
-                (*_NSGetArgc() as isize, *_NSGetArgv() as *const *const libc::c_char);
-            (0..argc as isize)
-                .map(|i| {
-                    let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec();
-                    OsStringExt::from_vec(bytes)
-                })
-                .collect::<Vec<_>>()
-        };
-        Args { iter: vec.into_iter() }
+    pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
+        // No need to initialize anything in here, `libdyld.dylib` has already
+        // done the work for us.
     }
 
-    // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
-    // and use underscores in their names - they're most probably
-    // are considered private and therefore should be avoided.
-    // Here is another way to get arguments using the Objective-C
-    // runtime.
-    //
-    // In general it looks like:
-    // res = Vec::new()
-    // let args = [[NSProcessInfo processInfo] arguments]
-    // for i in (0..[args count])
-    //      res.push([args objectAtIndex:i])
-    // res
-    #[cfg(not(target_os = "macos"))]
-    pub fn args() -> Args {
-        use crate::ffi::{c_char, c_void, OsString};
-        use crate::mem;
-        use crate::str;
-
-        type Sel = *const c_void;
-        type NsId = *const c_void;
-        type NSUInteger = usize;
-
+    pub fn argc_argv() -> (isize, *const *const c_char) {
         extern "C" {
-            fn sel_registerName(name: *const c_char) -> Sel;
-            fn objc_getClass(class_name: *const c_char) -> NsId;
-
-            // This must be transmuted to an appropriate function pointer type before being called.
-            fn objc_msgSend();
+            // These functions are in crt_externs.h.
+            fn _NSGetArgc() -> *mut c_int;
+            fn _NSGetArgv() -> *mut *mut *mut c_char;
         }
 
-        const MSG_SEND_PTR: unsafe extern "C" fn() = objc_msgSend;
-        const MSG_SEND_NO_ARGUMENTS_RETURN_PTR: unsafe extern "C" fn(NsId, Sel) -> *const c_void =
-            unsafe { mem::transmute(MSG_SEND_PTR) };
-        const MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER: unsafe extern "C" fn(
-            NsId,
-            Sel,
-        ) -> NSUInteger = unsafe { mem::transmute(MSG_SEND_PTR) };
-        const MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR: unsafe extern "C" fn(
-            NsId,
-            Sel,
-            NSUInteger,
-        )
-            -> *const c_void = unsafe { mem::transmute(MSG_SEND_PTR) };
+        // SAFETY: The returned pointer points to a static initialized early
+        // in the program lifetime by `libdyld.dylib`, and as such is always
+        // valid.
+        //
+        // NOTE: Similar to `_NSGetEnviron`, there technically isn't anything
+        // protecting us against concurrent modifications to this, and there
+        // doesn't exist a lock that we can take. Instead, it is generally
+        // expected that it's only modified in `main` / before other code
+        // runs, so reading this here should be fine.
+        let argc = unsafe { _NSGetArgc().read() };
+        // SAFETY: Same as above.
+        let argv = unsafe { _NSGetArgv().read() };
 
-        let mut res = Vec::new();
-
-        unsafe {
-            let process_info_sel = sel_registerName(c"processInfo".as_ptr());
-            let arguments_sel = sel_registerName(c"arguments".as_ptr());
-            let count_sel = sel_registerName(c"count".as_ptr());
-            let object_at_index_sel = sel_registerName(c"objectAtIndex:".as_ptr());
-            let utf8string_sel = sel_registerName(c"UTF8String".as_ptr());
-
-            let klass = objc_getClass(c"NSProcessInfo".as_ptr());
-            // `+[NSProcessInfo processInfo]` returns an object with +0 retain count, so no need to manually `retain/release`.
-            let info = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(klass, process_info_sel);
-
-            // `-[NSProcessInfo arguments]` returns an object with +0 retain count, so no need to manually `retain/release`.
-            let args = MSG_SEND_NO_ARGUMENTS_RETURN_PTR(info, arguments_sel);
-
-            let cnt = MSG_SEND_NO_ARGUMENTS_RETURN_NSUINTEGER(args, count_sel);
-            for i in 0..cnt {
-                // `-[NSArray objectAtIndex:]` returns an object whose lifetime is tied to the array, so no need to manually `retain/release`.
-                let ns_string =
-                    MSG_SEND_NSINTEGER_ARGUMENT_RETURN_PTR(args, object_at_index_sel, i);
-                // The lifetime of this pointer is tied to the NSString, as well as the current autorelease pool, which is why we heap-allocate the string below.
-                let utf_c_str: *const c_char =
-                    MSG_SEND_NO_ARGUMENTS_RETURN_PTR(ns_string, utf8string_sel).cast();
-                let bytes = CStr::from_ptr(utf_c_str).to_bytes();
-                res.push(OsString::from(str::from_utf8(bytes).unwrap()))
-            }
-        }
-
-        Args { iter: res.into_iter() }
+        // Cast from `*mut *mut c_char` to `*const *const c_char`
+        (argc as isize, argv.cast())
     }
 }
 
 #[cfg(any(target_os = "espidf", target_os = "vita"))]
 mod imp {
-    use super::Args;
+    use crate::ffi::c_char;
+    use crate::ptr;
 
     #[inline(always)]
     pub unsafe fn init(_argc: isize, _argv: *const *const u8) {}
 
-    pub fn args() -> Args {
-        Args { iter: Vec::new().into_iter() }
+    pub fn argc_argv() -> (isize, *const *const c_char) {
+        (0, ptr::null())
     }
 }
diff --git a/library/std/src/sys/pal/unix/mod.rs b/library/std/src/sys/pal/unix/mod.rs
index 21f233e..735ed96 100644
--- a/library/std/src/sys/pal/unix/mod.rs
+++ b/library/std/src/sys/pal/unix/mod.rs
@@ -399,14 +399,13 @@
         // Use libumem for the (malloc-compatible) allocator
         #[link(name = "umem")]
         extern "C" {}
-    } else if #[cfg(target_os = "macos")] {
+    } else if #[cfg(target_vendor = "apple")] {
+        // Link to `libSystem.dylib`.
+        //
+        // Don't get confused by the presence of `System.framework`,
+        // it is a deprecated wrapper over the dynamic library.
         #[link(name = "System")]
         extern "C" {}
-    } else if #[cfg(all(target_vendor = "apple", not(target_os = "macos")))] {
-        #[link(name = "System")]
-        #[link(name = "objc")]
-        #[link(name = "Foundation", kind = "framework")]
-        extern "C" {}
     } else if #[cfg(target_os = "fuchsia")] {
         #[link(name = "zircon")]
         #[link(name = "fdio")]
diff --git a/library/std/src/sys/pal/unix/os.rs b/library/std/src/sys/pal/unix/os.rs
index 3a28152..8afc49f 100644
--- a/library/std/src/sys/pal/unix/os.rs
+++ b/library/std/src/sys/pal/unix/os.rs
@@ -576,12 +576,36 @@
     }
 }
 
-#[cfg(target_os = "macos")]
+// Use `_NSGetEnviron` on Apple platforms.
+//
+// `_NSGetEnviron` is the documented alternative (see `man environ`), and has
+// been available since the first versions of both macOS and iOS.
+//
+// Nowadays, specifically since macOS 10.8, `environ` has been exposed through
+// `libdyld.dylib`, which is linked via. `libSystem.dylib`:
+// <https://github.com/apple-oss-distributions/dyld/blob/dyld-1160.6/libdyld/libdyldGlue.cpp#L913>
+//
+// So in the end, it likely doesn't really matter which option we use, but the
+// performance cost of using `_NSGetEnviron` is extremely miniscule, and it
+// might be ever so slightly more supported, so let's just use that.
+//
+// NOTE: The header where this is defined (`crt_externs.h`) was added to the
+// iOS 13.0 SDK, which has been the source of a great deal of confusion in the
+// past about the availability of this API.
+//
+// NOTE(madsmtm): Neither this nor using `environ` has been verified to not
+// cause App Store rejections; if this is found to be the case, an alternative
+// implementation of this is possible using `[NSProcessInfo environment]`
+// - which internally uses `_NSGetEnviron` and a system-wide lock on the
+// environment variables to protect against `setenv`, so using that might be
+// desirable anyhow? Though it also means that we have to link to Foundation.
+#[cfg(target_vendor = "apple")]
 pub unsafe fn environ() -> *mut *const *const c_char {
     libc::_NSGetEnviron() as *mut *const *const c_char
 }
 
-#[cfg(not(target_os = "macos"))]
+// Use the `environ` static which is part of POSIX.
+#[cfg(not(target_vendor = "apple"))]
 pub unsafe fn environ() -> *mut *const *const c_char {
     extern "C" {
         static mut environ: *const *const c_char;
diff --git a/library/std/src/sys/pal/unix/rand.rs b/library/std/src/sys/pal/unix/rand.rs
index d8f227b..e6df109 100644
--- a/library/std/src/sys/pal/unix/rand.rs
+++ b/library/std/src/sys/pal/unix/rand.rs
@@ -59,7 +59,14 @@
         unsafe { getrandom(buf.as_mut_ptr().cast(), buf.len(), libc::GRND_NONBLOCK) }
     }
 
-    #[cfg(any(target_os = "espidf", target_os = "horizon", target_os = "freebsd", netbsd10))]
+    #[cfg(any(
+        target_os = "espidf",
+        target_os = "horizon",
+        target_os = "freebsd",
+        netbsd10,
+        target_os = "illumos",
+        target_os = "solaris"
+    ))]
     fn getrandom(buf: &mut [u8]) -> libc::ssize_t {
         unsafe { libc::getrandom(buf.as_mut_ptr().cast(), buf.len(), 0) }
     }
@@ -83,6 +90,8 @@
         target_os = "horizon",
         target_os = "freebsd",
         target_os = "dragonfly",
+        target_os = "solaris",
+        target_os = "illumos",
         netbsd10
     )))]
     fn getrandom_fill_bytes(_buf: &mut [u8]) -> bool {
@@ -96,6 +105,8 @@
         target_os = "horizon",
         target_os = "freebsd",
         target_os = "dragonfly",
+        target_os = "solaris",
+        target_os = "illumos",
         netbsd10
     ))]
     fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
diff --git a/library/stdarch b/library/stdarch
index c0257c1..df3618d 160000
--- a/library/stdarch
+++ b/library/stdarch
@@ -1 +1 @@
-Subproject commit c0257c1660e78c80ad1b9136fcc5555b14da5b4c
+Subproject commit df3618d9f35165f4bc548114e511c49c29e1fd9b
diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml
index 6ff24a8..1ddacd9 100644
--- a/library/sysroot/Cargo.toml
+++ b/library/sysroot/Cargo.toml
@@ -22,6 +22,7 @@
 system-llvm-libunwind = ["std/system-llvm-libunwind"]
 panic-unwind = ["std/panic_unwind"]
 panic_immediate_abort = ["std/panic_immediate_abort"]
+optimize_for_size = ["std/optimize_for_size"]
 profiler = ["std/profiler"]
 std_detect_file_io = ["std/std_detect_file_io"]
 std_detect_dlsym_getauxval = ["std/std_detect_dlsym_getauxval"]
diff --git a/library/test/src/bench.rs b/library/test/src/bench.rs
index 23925e6..9a5dc35 100644
--- a/library/test/src/bench.rs
+++ b/library/test/src/bench.rs
@@ -68,12 +68,12 @@
     use std::fmt::Write;
     let mut output = String::new();
 
-    let median = bs.ns_iter_summ.median as usize;
-    let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
+    let median = bs.ns_iter_summ.median;
+    let deviation = bs.ns_iter_summ.max - bs.ns_iter_summ.min;
 
     write!(
         output,
-        "{:>11} ns/iter (+/- {})",
+        "{:>14} ns/iter (+/- {})",
         fmt_thousands_sep(median, ','),
         fmt_thousands_sep(deviation, ',')
     )
@@ -85,24 +85,27 @@
 }
 
 // Format a number with thousands separators
-fn fmt_thousands_sep(mut n: usize, sep: char) -> String {
+fn fmt_thousands_sep(mut n: f64, sep: char) -> String {
     use std::fmt::Write;
     let mut output = String::new();
     let mut trailing = false;
     for &pow in &[9, 6, 3, 0] {
         let base = 10_usize.pow(pow);
-        if pow == 0 || trailing || n / base != 0 {
-            if !trailing {
-                write!(output, "{}", n / base).unwrap();
-            } else {
-                write!(output, "{:03}", n / base).unwrap();
+        if pow == 0 || trailing || n / base as f64 >= 1.0 {
+            match (pow, trailing) {
+                // modern CPUs can execute multiple instructions per nanosecond
+                // e.g. benching an ADD takes about 0.25ns.
+                (0, true) => write!(output, "{:06.2}", n / base as f64).unwrap(),
+                (0, false) => write!(output, "{:.2}", n / base as f64).unwrap(),
+                (_, true) => write!(output, "{:03}", n as usize / base).unwrap(),
+                _ => write!(output,  "{}", n as usize / base).unwrap()
             }
             if pow != 0 {
                 output.push(sep);
             }
             trailing = true;
         }
-        n %= base;
+        n %= base as f64;
     }
 
     output
diff --git a/library/test/src/formatters/json.rs b/library/test/src/formatters/json.rs
index 47c4e77..6245aae 100644
--- a/library/test/src/formatters/json.rs
+++ b/library/test/src/formatters/json.rs
@@ -167,8 +167,8 @@
             ),
 
             TestResult::TrBench(ref bs) => {
-                let median = bs.ns_iter_summ.median as usize;
-                let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize;
+                let median = bs.ns_iter_summ.median;
+                let deviation = bs.ns_iter_summ.max - bs.ns_iter_summ.min;
 
                 let mbps = if bs.mb_s == 0 {
                     String::new()
diff --git a/rustfmt.toml b/rustfmt.toml
index 850d01e..ef56059 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -40,6 +40,7 @@
     "src/tools/clippy",
     "src/tools/miri",
     "src/tools/rust-analyzer",
+    "src/tools/rustc-perf",
     "src/tools/rustfmt",
 
     # these are ignored by a standard cargo fmt run
diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock
index 4a5d768..127699b 100644
--- a/src/bootstrap/Cargo.lock
+++ b/src/bootstrap/Cargo.lock
@@ -341,9 +341,9 @@
 
 [[package]]
 name = "libc"
-version = "0.2.151"
+version = "0.2.155"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
 
 [[package]]
 name = "linux-raw-sys"
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index e464e44..e60e8f0 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -3,7 +3,6 @@
 import contextlib
 import datetime
 import hashlib
-import json
 import os
 import re
 import shutil
@@ -52,7 +51,7 @@
 
     try:
         if url not in checksums:
-            raise RuntimeError(("src/stage0.json doesn't contain a checksum for {}. "
+            raise RuntimeError(("src/stage0 doesn't contain a checksum for {}. "
                                 "Pre-built artifacts might not be available for this "
                                 "target at this time, see https://doc.rust-lang.org/nightly"
                                 "/rustc/platform-support.html for more information.")
@@ -421,9 +420,9 @@
 
 
 class Stage0Toolchain:
-    def __init__(self, stage0_payload):
-        self.date = stage0_payload["date"]
-        self.version = stage0_payload["version"]
+    def __init__(self, date, version):
+        self.date = date
+        self.version = version
 
     def channel(self):
         return self.version + "-" + self.date
@@ -439,7 +438,7 @@
         bin_root,
         tarball_path,
         tarball_suffix,
-        checksums_sha256,
+        stage0_data,
         pattern,
         verbose,
     ):
@@ -448,7 +447,7 @@
         self.bin_root = bin_root
         self.tarball_path = tarball_path
         self.tarball_suffix = tarball_suffix
-        self.checksums_sha256 = checksums_sha256
+        self.stage0_data = stage0_data
         self.pattern = pattern
         self.verbose = verbose
 
@@ -458,7 +457,7 @@
             download_info.base_download_url,
             download_info.download_path,
             download_info.tarball_path,
-            download_info.checksums_sha256,
+            download_info.stage0_data,
             verbose=download_info.verbose,
         )
 
@@ -510,11 +509,12 @@
         build_dir = args.build_dir or self.get_toml('build-dir', 'build') or 'build'
         self.build_dir = os.path.abspath(build_dir)
 
-        with open(os.path.join(self.rust_root, "src", "stage0.json")) as f:
-            data = json.load(f)
-        self.checksums_sha256 = data["checksums_sha256"]
-        self.stage0_compiler = Stage0Toolchain(data["compiler"])
-        self.download_url = os.getenv("RUSTUP_DIST_SERVER") or data["config"]["dist_server"]
+        self.stage0_data = parse_stage0_file(os.path.join(self.rust_root, "src", "stage0"))
+        self.stage0_compiler = Stage0Toolchain(
+            self.stage0_data["compiler_date"],
+            self.stage0_data["compiler_version"]
+        )
+        self.download_url = os.getenv("RUSTUP_DIST_SERVER") or self.stage0_data["dist_server"]
 
         self.build = args.build or self.build_triple()
 
@@ -581,7 +581,7 @@
                     bin_root=self.bin_root(),
                     tarball_path=os.path.join(rustc_cache, filename),
                     tarball_suffix=tarball_suffix,
-                    checksums_sha256=self.checksums_sha256,
+                    stage0_data=self.stage0_data,
                     pattern=pattern,
                     verbose=self.verbose,
                 )
@@ -1071,6 +1071,16 @@
 
     return parser.parse_known_args(args)[0]
 
+def parse_stage0_file(path):
+    result = {}
+    with open(path, 'r') as file:
+        for line in file:
+            line = line.strip()
+            if line and not line.startswith('#'):
+                key, value = line.split('=', 1)
+                result[key.strip()] = value.strip()
+    return result
+
 def bootstrap(args):
     """Configure, fetch, build and run the initial bootstrap"""
     rust_root = os.path.abspath(os.path.join(__file__, '../../..'))
diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml
index d93c5fd..fd2da24 100644
--- a/src/bootstrap/defaults/config.compiler.toml
+++ b/src/bootstrap/defaults/config.compiler.toml
@@ -8,6 +8,8 @@
 # where adding `debug!()` appears to do nothing.
 # However, it makes running the compiler slightly slower.
 debug-logging = true
+# Get actually-useful information from backtraces, profiling, etc. with minimal added bytes
+debuginfo-level = "line-tables-only"
 # This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower.
 incremental = true
 # Print backtrace on internal compiler errors during bootstrap
diff --git a/src/bootstrap/src/bin/rustc.rs b/src/bootstrap/src/bin/rustc.rs
index 4b182a7..d227419 100644
--- a/src/bootstrap/src/bin/rustc.rs
+++ b/src/bootstrap/src/bin/rustc.rs
@@ -91,12 +91,13 @@
         rustc_real
     };
 
-    let mut cmd = if let Some(wrapper) = env::var_os("RUSTC_WRAPPER_REAL") {
-        let mut cmd = Command::new(wrapper);
-        cmd.arg(rustc_driver);
-        cmd
-    } else {
-        Command::new(rustc_driver)
+    let mut cmd = match env::var_os("RUSTC_WRAPPER_REAL") {
+        Some(wrapper) if !wrapper.is_empty() => {
+            let mut cmd = Command::new(wrapper);
+            cmd.arg(rustc_driver);
+            cmd
+        }
+        _ => Command::new(rustc_driver),
     };
     cmd.args(&args).env(dylib_path_var(), env::join_paths(&dylib_path).unwrap());
 
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 48a6602..66692a2 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1136,6 +1136,11 @@
         cargo.env("CFG_DEFAULT_LINKER", s);
     }
 
+    // Enable rustc's env var for `rust-lld` when requested.
+    if builder.config.lld_enabled {
+        cargo.env("CFG_USE_SELF_CONTAINED_LINKER", "1");
+    }
+
     if builder.config.rust_verify_llvm_ir {
         cargo.env("RUSTC_VERIFY_LLVM_IR", "1");
     }
diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs
index 5bc9d76..91039d0 100644
--- a/src/bootstrap/src/core/build_steps/dist.rs
+++ b/src/bootstrap/src/core/build_steps/dist.rs
@@ -26,7 +26,9 @@
 use crate::core::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::TargetSelection;
 use crate::utils::channel::{self, Info};
-use crate::utils::helpers::{exe, is_dylib, output, t, target_supports_cranelift_backend, timeit};
+use crate::utils::helpers::{
+    exe, is_dylib, move_file, output, t, target_supports_cranelift_backend, timeit,
+};
 use crate::utils::tarball::{GeneratedTarball, OverlayKind, Tarball};
 use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS};
 
@@ -1008,6 +1010,9 @@
         if builder.rust_info().is_managed_git_subrepository()
             || builder.rust_info().is_from_tarball()
         {
+            // FIXME: This code looks _very_ similar to what we have in `src/core/build_steps/vendor.rs`
+            // perhaps it should be removed in favor of making `dist` perform the `vendor` step?
+
             // Ensure we have all submodules from src and other directories checked out.
             for submodule in builder.get_all_submodules() {
                 builder.update_submodule(Path::new(submodule));
@@ -1027,6 +1032,10 @@
                 .arg(builder.src.join("./compiler/rustc_codegen_gcc/Cargo.toml"))
                 .arg("--sync")
                 .arg(builder.src.join("./src/bootstrap/Cargo.toml"))
+                .arg("--sync")
+                .arg(builder.src.join("./src/tools/opt-dist/Cargo.toml"))
+                .arg("--sync")
+                .arg(builder.src.join("./src/tools/rustc-perf/Cargo.toml"))
                 // Will read the libstd Cargo.toml
                 // which uses the unstable `public-dependency` feature.
                 .env("RUSTC_BOOTSTRAP", "1")
@@ -2024,7 +2033,7 @@
             builder.run(&mut cmd);
 
             if !builder.config.dry_run() {
-                t!(fs::rename(exe.join(&filename), distdir(builder).join(&filename)));
+                t!(move_file(exe.join(&filename), distdir(builder).join(&filename)));
             }
         }
     }
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index 3af1a05..8ca7af2 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -508,7 +508,7 @@
             cfg.define("LLVM_VERSION_SUFFIX", suffix);
         }
 
-        configure_cmake(builder, target, &mut cfg, true, ldflags, &[], &[]);
+        configure_cmake(builder, target, &mut cfg, true, ldflags, &[]);
         configure_llvm(builder, target, &mut cfg);
 
         for (key, val) in &builder.config.llvm_build_config {
@@ -597,7 +597,6 @@
     cfg: &mut cmake::Config,
     use_compiler_launcher: bool,
     mut ldflags: LdFlags,
-    extra_compiler_flags: &[&str],
     suppressed_compiler_flag_prefixes: &[&str],
 ) {
     // Do not print installation messages for up-to-date files.
@@ -751,9 +750,6 @@
     if builder.config.llvm_clang_cl.is_some() {
         cflags.push(&format!(" --target={target}"));
     }
-    for flag in extra_compiler_flags {
-        cflags.push(&format!(" {flag}"));
-    }
     cfg.define("CMAKE_C_FLAGS", cflags);
     let mut cxxflags: OsString = builder
         .cflags(target, GitRepo::Llvm, CLang::Cxx)
@@ -773,9 +769,6 @@
     if builder.config.llvm_clang_cl.is_some() {
         cxxflags.push(&format!(" --target={target}"));
     }
-    for flag in extra_compiler_flags {
-        cxxflags.push(&format!(" {flag}"));
-    }
     cfg.define("CMAKE_CXX_FLAGS", cxxflags);
     if let Some(ar) = builder.ar(target) {
         if ar.is_absolute() {
@@ -944,7 +937,7 @@
             ldflags.push_all("-Wl,-rpath,'$ORIGIN/../../../'");
         }
 
-        configure_cmake(builder, target, &mut cfg, true, ldflags, &[], &[]);
+        configure_cmake(builder, target, &mut cfg, true, ldflags, &[]);
         configure_llvm(builder, target, &mut cfg);
 
         // Re-use the same flags as llvm to control the level of debug information
@@ -1043,8 +1036,6 @@
         // Unfortunately sccache currently lacks support to build them successfully.
         // Disable compiler launcher on Darwin targets to avoid potential issues.
         let use_compiler_launcher = !self.target.contains("apple-darwin");
-        let extra_compiler_flags: &[&str] =
-            if self.target.contains("apple") { &["-fembed-bitcode=off"] } else { &[] };
         // Since v1.0.86, the cc crate adds -mmacosx-version-min to the default
         // flags on MacOS. A long-standing bug in the CMake rules for compiler-rt
         // causes architecture detection to be skipped when this flag is present,
@@ -1057,7 +1048,6 @@
             &mut cfg,
             use_compiler_launcher,
             LdFlags::default(),
-            extra_compiler_flags,
             suppressed_compiler_flag_prefixes,
         );
 
diff --git a/src/bootstrap/src/core/build_steps/synthetic_targets.rs b/src/bootstrap/src/core/build_steps/synthetic_targets.rs
index 89d50b5..281a9b0 100644
--- a/src/bootstrap/src/core/build_steps/synthetic_targets.rs
+++ b/src/bootstrap/src/core/build_steps/synthetic_targets.rs
@@ -80,8 +80,5 @@
     customize(spec_map);
 
     std::fs::write(&path, serde_json::to_vec_pretty(&spec).unwrap()).unwrap();
-    let target = TargetSelection::create_synthetic(&name, path.to_str().unwrap());
-    crate::utils::cc_detect::find_target(builder, target);
-
-    target
+    TargetSelection::create_synthetic(&name, path.to_str().unwrap())
 }
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 21344a4..2db3f8f 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -1,6 +1,6 @@
 use std::env;
 use std::fs;
-use std::path::PathBuf;
+use std::path::{Path, PathBuf};
 use std::process::Command;
 
 use crate::core::build_steps::compile;
@@ -313,10 +313,47 @@
     SuggestTests, "src/tools/suggest-tests", "suggest-tests";
     GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys";
     RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = "test";
-    OptimizedDist, "src/tools/opt-dist", "opt-dist";
     CoverageDump, "src/tools/coverage-dump", "coverage-dump";
 );
 
+#[derive(Debug, Clone, Hash, PartialEq, Eq)]
+pub struct OptimizedDist {
+    pub compiler: Compiler,
+    pub target: TargetSelection,
+}
+
+impl Step for OptimizedDist {
+    type Output = PathBuf;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.path("src/tools/opt-dist")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        run.builder.ensure(OptimizedDist {
+            compiler: run.builder.compiler(0, run.builder.config.build),
+            target: run.target,
+        });
+    }
+
+    fn run(self, builder: &Builder<'_>) -> PathBuf {
+        // We need to ensure the rustc-perf submodule is initialized when building opt-dist since
+        // the tool requires it to be in place to run.
+        builder.update_submodule(Path::new("src/tools/rustc-perf"));
+
+        builder.ensure(ToolBuild {
+            compiler: self.compiler,
+            target: self.target,
+            tool: "opt-dist",
+            mode: Mode::ToolBootstrap,
+            path: "src/tools/opt-dist",
+            source_type: SourceType::InTree,
+            extra_features: Vec::new(),
+            allow_features: "",
+        })
+    }
+}
+
 #[derive(Debug, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
 pub struct ErrorIndex {
     pub compiler: Compiler,
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 6c4b26e..045cde5 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -88,6 +88,9 @@
 
     /// Primary function to execute this rule. Can call `builder.ensure()`
     /// with other steps to run those.
+    ///
+    /// This gets called twice during a normal `./x.py` execution: first
+    /// with `dry_run() == true`, and then for real.
     fn run(self, builder: &Builder<'_>) -> Self::Output;
 
     /// When bootstrap is passed a set of paths, this controls whether this rule
@@ -317,11 +320,13 @@
     (
         "tests",
         &[
+            // tidy-alphabetical-start
             "tests/assembly",
             "tests/codegen",
             "tests/codegen-units",
             "tests/coverage",
             "tests/coverage-run-rustdoc",
+            "tests/crashes",
             "tests/debuginfo",
             "tests/incremental",
             "tests/mir-opt",
@@ -337,6 +342,7 @@
             "tests/rustdoc-ui",
             "tests/ui",
             "tests/ui-fulldeps",
+            // tidy-alphabetical-end
         ],
     ),
 ];
@@ -2549,7 +2555,12 @@
         // FIXME: the guard against msvc shouldn't need to be here
         if target.is_msvc() {
             if let Some(ref cl) = builder.config.llvm_clang_cl {
-                self.command.env("CC", cl).env("CXX", cl);
+                // FIXME: There is a bug in Clang 18 when building for ARM64:
+                // https://github.com/llvm/llvm-project/pull/81849. This is
+                // fixed in LLVM 19, but can't be backported.
+                if !target.starts_with("aarch64") && !target.starts_with("arm64ec") {
+                    self.command.env("CC", cl).env("CXX", cl);
+                }
             }
         } else {
             let ccache = builder.config.ccache.as_ref();
diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs
index 9898d49..9710365 100644
--- a/src/bootstrap/src/core/builder/tests.rs
+++ b/src/bootstrap/src/core/builder/tests.rs
@@ -129,6 +129,26 @@
 }
 
 #[test]
+fn check_missing_paths_for_x_test_tests() {
+    let build = Build::new(configure("test", &["A-A"], &["A-A"]));
+
+    let (_, tests_remap_paths) =
+        PATH_REMAP.iter().find(|(target_path, _)| *target_path == "tests").unwrap();
+
+    let tests_dir = fs::read_dir(build.src.join("tests")).unwrap();
+    for dir in tests_dir {
+        let path = dir.unwrap().path();
+
+        // Skip if not a test directory.
+        if path.ends_with("tests/auxiliary") || !path.is_dir() {
+            continue
+        }
+
+        assert!(tests_remap_paths.iter().any(|item| path.ends_with(*item)), "{} is missing in PATH_REMAP tests list.", path.display());
+    }
+}
+
+#[test]
 fn test_exclude() {
     let mut config = configure("test", &["A-A"], &["A-A"]);
     config.skip = vec!["src/tools/tidy".into()];
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index 0167c51..19119a0 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -181,7 +181,7 @@
     pub test_compare_mode: bool,
     pub color: Color,
     pub patch_binaries_for_nix: Option<bool>,
-    pub stage0_metadata: Stage0Metadata,
+    pub stage0_metadata: build_helper::stage0_parser::Stage0,
     pub android_ndk: Option<PathBuf>,
     /// Whether to use the `c` feature of the `compiler_builtins` crate.
     pub optimized_compiler_builtins: bool,
@@ -351,34 +351,6 @@
     pub paths: Vec<PathBuf>,
 }
 
-#[derive(Default, Deserialize, Clone)]
-pub struct Stage0Metadata {
-    pub compiler: CompilerMetadata,
-    pub config: Stage0Config,
-    pub checksums_sha256: HashMap<String, String>,
-    pub rustfmt: Option<RustfmtMetadata>,
-}
-#[derive(Default, Deserialize, Clone)]
-pub struct CompilerMetadata {
-    pub date: String,
-    pub version: String,
-}
-
-#[derive(Default, Deserialize, Clone)]
-pub struct Stage0Config {
-    pub dist_server: String,
-    pub artifacts_server: String,
-    pub artifacts_with_llvm_assertions_server: String,
-    pub git_merge_commit_email: String,
-    pub git_repository: String,
-    pub nightly_branch: String,
-}
-#[derive(Default, Deserialize, Clone)]
-pub struct RustfmtMetadata {
-    pub date: String,
-    pub version: String,
-}
-
 #[derive(Clone, Debug, Default)]
 pub enum RustfmtState {
     SystemToolchain(PathBuf),
@@ -1298,13 +1270,13 @@
                 Some(p) => PathBuf::from(p),
                 None => git_root,
             };
-            // If this doesn't have at least `stage0.json`, we guessed wrong. This can happen when,
+            // If this doesn't have at least `stage0`, we guessed wrong. This can happen when,
             // for example, the build directory is inside of another unrelated git directory.
             // In that case keep the original `CARGO_MANIFEST_DIR` handling.
             //
             // NOTE: this implies that downloadable bootstrap isn't supported when the build directory is outside
             // the source directory. We could fix that by setting a variable from all three of python, ./x, and x.ps1.
-            if git_root.join("src").join("stage0.json").exists() {
+            if git_root.join("src").join("stage0").exists() {
                 config.src = git_root;
             }
         } else {
@@ -1322,9 +1294,7 @@
             .to_path_buf();
         }
 
-        let stage0_json = t!(std::fs::read(config.src.join("src").join("stage0.json")));
-
-        config.stage0_metadata = t!(serde_json::from_slice::<Stage0Metadata>(&stage0_json));
+        config.stage0_metadata = build_helper::stage0_parser::parse_stage0_file();
 
         // Read from `--config`, then `RUST_BOOTSTRAP_CONFIG`, then `./config.toml`, then `config.toml` in the root directory.
         let toml_path = flags
@@ -1337,6 +1307,9 @@
             toml_path = config.src.join(toml_path);
         }
 
+        let file_content = t!(fs::read_to_string(config.src.join("src/ci/channel")));
+        let ci_channel = file_content.trim_end();
+
         // Give a hard error if `--config` or `RUST_BOOTSTRAP_CONFIG` are set to a missing path,
         // but not if `config.toml` hasn't been created.
         let mut toml = if !using_default_path || toml_path.exists() {
@@ -1562,7 +1535,9 @@
         let mut debuginfo_level_tests = None;
         let mut optimize = None;
         let mut omit_git_hash = None;
+        let mut lld_enabled = None;
 
+        let mut is_user_configured_rust_channel = false;
         if let Some(rust) = toml.rust {
             let Rust {
                 optimize: optimize_toml,
@@ -1595,7 +1570,7 @@
                 dist_src,
                 save_toolstates,
                 codegen_backends,
-                lld,
+                lld: lld_enabled_toml,
                 llvm_tools,
                 llvm_bitcode_linker,
                 deny_warnings,
@@ -1620,6 +1595,7 @@
                 lld_mode,
             } = rust;
 
+            is_user_configured_rust_channel = channel.is_some();
             set(&mut config.channel, channel);
 
             config.download_rustc_commit = config.download_ci_rustc_commit(download_rustc);
@@ -1627,8 +1603,6 @@
             if config.download_rustc_commit.is_some() {
                 // We need the channel used by the downloaded compiler to match the one we set for rustdoc;
                 // otherwise rustdoc-ui tests break.
-                let ci_channel = t!(fs::read_to_string(config.src.join("src/ci/channel")));
-                let ci_channel = ci_channel.trim_end();
                 if config.channel != ci_channel
                     && !(config.channel == "dev" && ci_channel == "nightly")
                 {
@@ -1650,6 +1624,7 @@
             debuginfo_level_std = debuginfo_level_std_toml;
             debuginfo_level_tools = debuginfo_level_tools_toml;
             debuginfo_level_tests = debuginfo_level_tests_toml;
+            lld_enabled = lld_enabled_toml;
 
             config.rust_split_debuginfo_for_build_triple = split_debuginfo
                 .as_deref()
@@ -1683,18 +1658,8 @@
                 config.incremental = true;
             }
             set(&mut config.lld_mode, lld_mode);
-            set(&mut config.lld_enabled, lld);
             set(&mut config.llvm_bitcode_linker_enabled, llvm_bitcode_linker);
 
-            if matches!(config.lld_mode, LldMode::SelfContained)
-                && !config.lld_enabled
-                && flags.stage.unwrap_or(0) > 0
-            {
-                panic!(
-                    "Trying to use self-contained lld as a linker, but LLD is not being added to the sysroot. Enable it with rust.lld = true."
-                );
-            }
-
             config.llvm_tools_enabled = llvm_tools.unwrap_or(true);
             config.rustc_parallel =
                 parallel_compiler.unwrap_or(config.channel == "dev" || config.channel == "nightly");
@@ -1755,6 +1720,10 @@
         config.omit_git_hash = omit_git_hash.unwrap_or(default);
         config.rust_info = GitInfo::new(config.omit_git_hash, &config.src);
 
+        if config.rust_info.is_from_tarball() && !is_user_configured_rust_channel {
+            ci_channel.clone_into(&mut config.channel);
+        }
+
         if let Some(llvm) = toml.llvm {
             let Llvm {
                 optimize: optimize_toml,
@@ -1984,6 +1953,43 @@
         config.llvm_plugins = llvm_plugins.unwrap_or(false);
         config.rust_optimize = optimize.unwrap_or(RustOptimize::Bool(true));
 
+        // We make `x86_64-unknown-linux-gnu` use the self-contained linker by default, so we will
+        // build our internal lld and use it as the default linker, by setting the `rust.lld` config
+        // to true by default:
+        // - on the `x86_64-unknown-linux-gnu` target
+        // - on the `dev` and `nightly` channels
+        // - when building our in-tree llvm (i.e. the target has not set an `llvm-config`), so that
+        //   we're also able to build the corresponding lld
+        // - or when using an external llvm that's downloaded from CI, which also contains our prebuilt
+        //   lld
+        // - otherwise, we'd be using an external llvm, and lld would not necessarily available and
+        //   thus, disabled
+        // - similarly, lld will not be built nor used by default when explicitly asked not to, e.g.
+        //   when the config sets `rust.lld = false`
+        if config.build.triple == "x86_64-unknown-linux-gnu"
+            && config.hosts == [config.build]
+            && (config.channel == "dev" || config.channel == "nightly")
+        {
+            let no_llvm_config = config
+                .target_config
+                .get(&config.build)
+                .is_some_and(|target_config| target_config.llvm_config.is_none());
+            let enable_lld = config.llvm_from_ci || no_llvm_config;
+            // Prefer the config setting in case an explicit opt-out is needed.
+            config.lld_enabled = lld_enabled.unwrap_or(enable_lld);
+        } else {
+            set(&mut config.lld_enabled, lld_enabled);
+        }
+
+        if matches!(config.lld_mode, LldMode::SelfContained)
+            && !config.lld_enabled
+            && flags.stage.unwrap_or(0) > 0
+        {
+            panic!(
+                "Trying to use self-contained lld as a linker, but LLD is not being added to the sysroot. Enable it with rust.lld = true."
+            );
+        }
+
         let default = debug == Some(true);
         config.rust_debug_assertions = debug_assertions.unwrap_or(default);
         config.rust_debug_assertions_std =
diff --git a/src/bootstrap/src/core/download.rs b/src/bootstrap/src/core/download.rs
index 75e0f64..60f48c5 100644
--- a/src/bootstrap/src/core/download.rs
+++ b/src/bootstrap/src/core/download.rs
@@ -9,10 +9,10 @@
 };
 
 use build_helper::ci::CiEnv;
+use build_helper::stage0_parser::VersionMetadata;
 use xz2::bufread::XzDecoder;
 
-use crate::core::config::RustfmtMetadata;
-use crate::utils::helpers::{check_run, exe, program_out_of_date};
+use crate::utils::helpers::{check_run, exe, move_file, program_out_of_date};
 use crate::{core::build_steps::llvm::detect_llvm_sha, utils::helpers::hex_encode};
 use crate::{t, Config};
 
@@ -209,7 +209,7 @@
             None => panic!("no protocol in {url}"),
         }
         t!(
-            std::fs::rename(&tempfile, dest_path),
+            move_file(&tempfile, dest_path),
             format!("failed to rename {tempfile:?} to {dest_path:?}")
         );
     }
@@ -313,7 +313,7 @@
             if src_path.is_dir() && dst_path.exists() {
                 continue;
             }
-            t!(fs::rename(src_path, dst_path));
+            t!(move_file(src_path, dst_path));
         }
         let dst_dir = dst.join(directory_prefix);
         if dst_dir.exists() {
@@ -408,7 +408,7 @@
     /// NOTE: rustfmt is a completely different toolchain than the bootstrap compiler, so it can't
     /// reuse target directories or artifacts
     pub(crate) fn maybe_download_rustfmt(&self) -> Option<PathBuf> {
-        let RustfmtMetadata { date, version } = self.stage0_metadata.rustfmt.as_ref()?;
+        let VersionMetadata { date, version } = self.stage0_metadata.rustfmt.as_ref()?;
         let channel = format!("{version}-{date}");
 
         let host = self.build;
@@ -606,7 +606,7 @@
             DownloadSource::Dist => {
                 let dist_server = env::var("RUSTUP_DIST_SERVER")
                     .unwrap_or(self.stage0_metadata.config.dist_server.to_string());
-                // NOTE: make `dist` part of the URL because that's how it's stored in src/stage0.json
+                // NOTE: make `dist` part of the URL because that's how it's stored in src/stage0
                 (dist_server, format!("dist/{key}/{filename}"), true)
             }
         };
@@ -616,7 +616,7 @@
         // this on each and every nightly ...
         let checksum = if should_verify {
             let error = format!(
-                "src/stage0.json doesn't contain a checksum for {url}. \
+                "src/stage0 doesn't contain a checksum for {url}. \
                 Pre-built artifacts might not be available for this \
                 target at this time, see https://doc.rust-lang.org/nightly\
                 /rustc/platform-support.html for more information."
diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs
index 493ad99..9c3df6f 100644
--- a/src/bootstrap/src/core/sanity.rs
+++ b/src/bootstrap/src/core/sanity.rs
@@ -8,7 +8,7 @@
 //! In theory if we get past this phase it's a bug if a build fails, but in
 //! practice that's likely not true!
 
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 use std::env;
 use std::ffi::{OsStr, OsString};
 use std::fs;
@@ -33,8 +33,6 @@
 // Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap).
 const STAGE0_MISSING_TARGETS: &[&str] = &[
     // just a dummy comment so the list doesn't get onelined
-    "aarch64-apple-visionos",
-    "aarch64-apple-visionos-sim",
 ];
 
 impl Finder {
@@ -169,6 +167,12 @@
         .map(|p| cmd_finder.must_have(p))
         .or_else(|| cmd_finder.maybe_have("reuse"));
 
+    let stage0_supported_target_list: HashSet<String> =
+        output(Command::new(&build.config.initial_rustc).args(["--print", "target-list"]))
+            .lines()
+            .map(|s| s.to_string())
+            .collect();
+
     // We're gonna build some custom C code here and there, host triples
     // also build some C++ shims for LLVM so we need a C++ compiler.
     for target in &build.targets {
@@ -195,11 +199,19 @@
         if !["A-A", "B-B", "C-C"].contains(&target_str.as_str()) {
             let mut has_target = false;
 
-            let supported_target_list =
-                output(Command::new(&build.config.initial_rustc).args(["--print", "target-list"]));
+            let missing_targets_hashset: HashSet<_> = STAGE0_MISSING_TARGETS.iter().map(|t| t.to_string()).collect();
+            let duplicated_targets: Vec<_> = stage0_supported_target_list.intersection(&missing_targets_hashset).collect();
+
+            if !duplicated_targets.is_empty() {
+                println!("Following targets supported from the stage0 compiler, please remove them from STAGE0_MISSING_TARGETS list.");
+                for duplicated_target in duplicated_targets {
+                    println!("  {duplicated_target}");
+                }
+                std::process::exit(1);
+            }
 
             // Check if it's a built-in target.
-            has_target |= supported_target_list.contains(&target_str);
+            has_target |= stage0_supported_target_list.contains(&target_str);
             has_target |= STAGE0_MISSING_TARGETS.contains(&target_str.as_str());
 
             if !has_target {
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index 47b03d4..698a576 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -683,6 +683,8 @@
 
         if !self.config.dry_run() {
             {
+                // We first do a dry-run. This is a sanity-check to ensure that
+                // steps don't do anything expensive in the dry-run.
                 self.config.dry_run = DryRun::SelfCheck;
                 let builder = builder::Builder::new(self);
                 builder.execute_cli();
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index c3a0369..2f9eaf5 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -180,4 +180,14 @@
         severity: ChangeSeverity::Info,
         summary: "New option `build.lldb` that will override the default lldb binary path used in debuginfo tests",
     },
+    ChangeInfo {
+        change_id: 123337,
+        severity: ChangeSeverity::Info,
+        summary: r#"The compiler profile now defaults to rust.debuginfo-level = "line-tables-only""#,
+    },
+    ChangeInfo {
+        change_id: 124129,
+        severity: ChangeSeverity::Warning,
+        summary: "`rust.lld` has a new default value of `true` on `x86_64-unknown-linux-gnu`. Starting at stage1, `rust-lld` will thus be this target's default linker. No config changes should be necessary.",
+    },
 ];
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 0d2ff4f..278359c 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -150,6 +150,21 @@
     }
 }
 
+/// Rename a file if from and to are in the same filesystem or
+/// copy and remove the file otherwise
+pub fn move_file<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> {
+    match fs::rename(&from, &to) {
+        // FIXME: Once `ErrorKind::CrossesDevices` is stabilized use
+        // if e.kind() == io::ErrorKind::CrossesDevices {
+        #[cfg(unix)]
+        Err(e) if e.raw_os_error() == Some(libc::EXDEV) => {
+            std::fs::copy(&from, &to)?;
+            std::fs::remove_file(&from)
+        }
+        r => r,
+    }
+}
+
 pub fn forcing_clang_based_tests() -> bool {
     if let Some(var) = env::var_os("RUSTBUILD_FORCE_CLANG_BASED_TESTS") {
         match &var.to_string_lossy().to_lowercase()[..] {
diff --git a/src/bootstrap/src/utils/render_tests.rs b/src/bootstrap/src/utils/render_tests.rs
index 462b76d..5c9918b 100644
--- a/src/bootstrap/src/utils/render_tests.rs
+++ b/src/bootstrap/src/utils/render_tests.rs
@@ -215,8 +215,8 @@
             for bench in &self.benches {
                 rows.push((
                     &bench.name,
-                    format!("{:.2?}/iter", Duration::from_nanos(bench.median)),
-                    format!("+/- {:.2?}", Duration::from_nanos(bench.deviation)),
+                    format!("{:.2?}/iter", bench.median),
+                    format!("+/- {:.2?}", bench.deviation),
                 ));
             }
 
@@ -394,8 +394,8 @@
 #[derive(serde_derive::Deserialize)]
 struct BenchOutcome {
     name: String,
-    median: u64,
-    deviation: u64,
+    median: f64,
+    deviation: f64,
 }
 
 #[derive(serde_derive::Deserialize)]
diff --git a/src/bootstrap/src/utils/tarball.rs b/src/bootstrap/src/utils/tarball.rs
index 2a950e6..57cdf74 100644
--- a/src/bootstrap/src/utils/tarball.rs
+++ b/src/bootstrap/src/utils/tarball.rs
@@ -13,7 +13,7 @@
 use crate::core::builder::Builder;
 use crate::core::{build_steps::dist::distdir, builder::Kind};
 use crate::utils::channel;
-use crate::utils::helpers::t;
+use crate::utils::helpers::{move_file, t};
 
 #[derive(Copy, Clone)]
 pub(crate) enum OverlayKind {
@@ -284,7 +284,7 @@
         // name, not "image". We rename the image directory just before passing
         // into rust-installer.
         let dest = self.temp_dir.join(self.package_name());
-        t!(std::fs::rename(&self.image_dir, &dest));
+        t!(move_file(&self.image_dir, &dest));
 
         self.run(|this, cmd| {
             let distdir = distdir(this.builder);
diff --git a/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile
index dab0667..e718437 100644
--- a/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-armv7-linux/Dockerfile
@@ -25,5 +25,5 @@
 
 ENV HOSTS=armv7-unknown-linux-gnueabihf
 
-ENV RUST_CONFIGURE_ARGS --enable-full-tools --disable-docs
+ENV RUST_CONFIGURE_ARGS --enable-full-tools --enable-profiler --disable-docs
 ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
index fe84c23..4e1aae9 100644
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile
@@ -58,14 +58,6 @@
 RUN ./build-clang.sh
 ENV CC=clang CXX=clang++
 
-# rustc-perf version from 2023-10-22
-# Should also be changed in the opt-dist tool for other environments.
-ENV PERF_COMMIT 4f313add609f43e928e98132358e8426ed3969ae
-RUN curl -LS -o perf.zip https://ci-mirrors.rust-lang.org/rustc/rustc-perf-$PERF_COMMIT.zip && \
-    unzip perf.zip && \
-    mv rustc-perf-$PERF_COMMIT rustc-perf && \
-    rm perf.zip
-
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
 
diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
index 005f453..f3591a6 100755
--- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
+++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
@@ -4,6 +4,7 @@
 
 source shared.sh
 
+# Try to keep the LLVM version here in sync with src/ci/scripts/install-clang.sh
 LLVM=llvmorg-18.1.0
 
 mkdir llvm-project
diff --git a/src/ci/docker/scripts/x86_64-gnu-llvm.sh b/src/ci/docker/scripts/x86_64-gnu-llvm.sh
index 2eb751c..876b300 100755
--- a/src/ci/docker/scripts/x86_64-gnu-llvm.sh
+++ b/src/ci/docker/scripts/x86_64-gnu-llvm.sh
@@ -23,6 +23,10 @@
     # Run `ui-fulldeps` in `--stage=1`, which actually uses the stage0
     # compiler, and is sensitive to the addition of new flags.
     ../x.py --stage 1 test tests/ui-fulldeps
+
+    # The tests are run a second time with the size optimizations enabled.
+    ../x.py --stage 1 test library/std library/alloc library/core \
+        --rustc-args "--cfg feature=\"optimize_for_size\""
 fi
 
 # When running gcc backend tests, we need to install `libgccjit` and to not run llvm codegen
diff --git a/src/ci/github-actions/calculate-job-matrix.py b/src/ci/github-actions/calculate-job-matrix.py
index 68565f4..4f9bc39 100755
--- a/src/ci/github-actions/calculate-job-matrix.py
+++ b/src/ci/github-actions/calculate-job-matrix.py
@@ -8,10 +8,11 @@
 and filters them based on the event that happened on CI.
 """
 import dataclasses
-import enum
 import json
 import logging
 import os
+import re
+import typing
 from pathlib import Path
 from typing import List, Dict, Any, Optional
 
@@ -44,10 +45,22 @@
     return jobs
 
 
-class WorkflowRunType(enum.Enum):
-    PR = enum.auto()
-    Try = enum.auto()
-    Auto = enum.auto()
+@dataclasses.dataclass
+class PRRunType:
+    pass
+
+
+@dataclasses.dataclass
+class TryRunType:
+    custom_jobs: List[str]
+
+
+@dataclasses.dataclass
+class AutoRunType:
+    pass
+
+
+WorkflowRunType = typing.Union[PRRunType, TryRunType, AutoRunType]
 
 
 @dataclasses.dataclass
@@ -55,11 +68,28 @@
     event_name: str
     ref: str
     repository: str
+    commit_message: Optional[str]
+
+
+def get_custom_jobs(ctx: GitHubCtx) -> List[str]:
+    """
+    Tries to parse names of specific CI jobs that should be executed in the form of
+    try-job: <job-name>
+    from the commit message of the passed GitHub context.
+    """
+    if ctx.commit_message is None:
+        return []
+
+    regex = re.compile(r"^try-job: (.*)", re.MULTILINE)
+    jobs = []
+    for match in regex.finditer(ctx.commit_message):
+        jobs.append(match.group(1))
+    return jobs
 
 
 def find_run_type(ctx: GitHubCtx) -> Optional[WorkflowRunType]:
     if ctx.event_name == "pull_request":
-        return WorkflowRunType.PR
+        return PRRunType()
     elif ctx.event_name == "push":
         old_bors_try_build = (
             ctx.ref in ("refs/heads/try", "refs/heads/try-perf") and
@@ -72,20 +102,41 @@
         try_build = old_bors_try_build or new_bors_try_build
 
         if try_build:
-            return WorkflowRunType.Try
+            jobs = get_custom_jobs(ctx)
+            return TryRunType(custom_jobs=jobs)
 
         if ctx.ref == "refs/heads/auto" and ctx.repository == "rust-lang-ci/rust":
-            return WorkflowRunType.Auto
+            return AutoRunType()
 
     return None
 
 
 def calculate_jobs(run_type: WorkflowRunType, job_data: Dict[str, Any]) -> List[Job]:
-    if run_type == WorkflowRunType.PR:
+    if isinstance(run_type, PRRunType):
         return add_base_env(name_jobs(job_data["pr"], "PR"), job_data["envs"]["pr"])
-    elif run_type == WorkflowRunType.Try:
-        return add_base_env(name_jobs(job_data["try"], "try"), job_data["envs"]["try"])
-    elif run_type == WorkflowRunType.Auto:
+    elif isinstance(run_type, TryRunType):
+        jobs = job_data["try"]
+        custom_jobs = run_type.custom_jobs
+        if custom_jobs:
+            if len(custom_jobs) > 10:
+                raise Exception(
+                    f"It is only possible to schedule up to 10 custom jobs, "
+                    f"received {len(custom_jobs)} jobs"
+                )
+
+            jobs = []
+            unknown_jobs = []
+            for custom_job in custom_jobs:
+                job = [j for j in job_data["auto"] if j["image"] == custom_job]
+                if not job:
+                    unknown_jobs.append(custom_job)
+                    continue
+                jobs.append(job[0])
+            if unknown_jobs:
+                raise Exception(f"Custom job(s) `{unknown_jobs}` not found in auto jobs")
+
+        return add_base_env(name_jobs(jobs, "try"), job_data["envs"]["try"])
+    elif isinstance(run_type, AutoRunType):
         return add_base_env(name_jobs(job_data["auto"], "auto"), job_data["envs"]["auto"])
 
     return []
@@ -99,19 +150,25 @@
 
 
 def get_github_ctx() -> GitHubCtx:
+    event_name = os.environ["GITHUB_EVENT_NAME"]
+
+    commit_message = None
+    if event_name == "push":
+        commit_message = os.environ["COMMIT_MESSAGE"]
     return GitHubCtx(
-        event_name=os.environ["GITHUB_EVENT_NAME"],
+        event_name=event_name,
         ref=os.environ["GITHUB_REF"],
-        repository=os.environ["GITHUB_REPOSITORY"]
+        repository=os.environ["GITHUB_REPOSITORY"],
+        commit_message=commit_message
     )
 
 
 def format_run_type(run_type: WorkflowRunType) -> str:
-    if run_type == WorkflowRunType.PR:
+    if isinstance(run_type, PRRunType):
         return "pr"
-    elif run_type == WorkflowRunType.Auto:
+    elif isinstance(run_type, AutoRunType):
         return "auto"
-    elif run_type == WorkflowRunType.Try:
+    elif isinstance(run_type, TryRunType):
         return "try"
     else:
         raise AssertionError()
@@ -135,6 +192,10 @@
     if run_type is not None:
         jobs = calculate_jobs(run_type, data)
     jobs = skip_jobs(jobs, channel)
+
+    if not jobs:
+        raise Exception("Scheduled job list is empty, this is an error")
+
     run_type = format_run_type(run_type)
 
     logging.info(f"Output:\n{yaml.dump(dict(jobs=jobs, run_type=run_type), indent=4)}")
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 20b1a55..05470ee 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -32,14 +32,6 @@
     os: windows-2022-16core-64gb
     <<: *base-job
 
-  - &job-windows-2019-8c
-    os: windows-2019-8core-32gb
-    <<: *base-job
-
-  - &job-windows-2019-16c
-    os: windows-2019-16core-64gb
-    <<: *base-job
-
   - &job-aarch64-linux
     os: [ self-hosted, ARM64, linux ]
 
@@ -58,8 +50,6 @@
   production:
     &production
     DEPLOY_BUCKET: rust-lang-ci2
-    TOOLSTATE_ISSUES_API_URL: https://api.github.com/repos/rust-lang/rust/issues
-    TOOLSTATE_PUBLISH: 1
     # AWS_SECRET_ACCESS_KEYs are stored in GitHub's secrets storage, named
     # AWS_SECRET_ACCESS_KEY_<keyid>. Including the key id in the name allows to
     # rotate them in a single branch while keeping the old key in another
@@ -116,66 +106,66 @@
     <<: *job-aarch64-linux
 
   - image: arm-android
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: armhf-gnu
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-aarch64-linux
     env:
       CODEGEN_BACKENDS: llvm,cranelift
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-android
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-arm-linux
-    <<: *job-linux-16c
+    <<: *job-linux-8c
 
   - image: dist-armhf-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-armv7-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-i586-gnu-i586-i686-musl
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-i686-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-loongarch64-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-ohos
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-powerpc-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-powerpc64-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-powerpc64le-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-riscv64-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-s390x-linux
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-various-1
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-various-2
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-x86_64-freebsd
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-x86_64-illumos
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: dist-x86_64-linux
     env:
@@ -194,7 +184,7 @@
     <<: *job-linux-8c
 
   - image: dist-x86_64-netbsd
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: i686-gnu
     <<: *job-linux-8c
@@ -206,7 +196,7 @@
     <<: *job-linux-4c
 
   - image: test-various
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: x86_64-gnu
     <<: *job-linux-4c
@@ -237,7 +227,7 @@
     <<: *job-linux-8c
 
   - image: x86_64-gnu-debug
-    <<: *job-linux-8c
+    <<: *job-linux-4c
 
   - image: x86_64-gnu-distcheck
     <<: *job-linux-8c
@@ -349,13 +339,13 @@
     env:
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-profiler
       SCRIPT: make ci-msvc
-    <<: *job-windows-2019-8c
+    <<: *job-windows-8c
 
   - image: i686-msvc
     env:
       RUST_CONFIGURE_ARGS: --build=i686-pc-windows-msvc
       SCRIPT: make ci-msvc
-    <<: *job-windows-2019-8c
+    <<: *job-windows-8c
 
   - image: x86_64-msvc-ext
     env:
@@ -363,7 +353,7 @@
       HOST_TARGET: x86_64-pc-windows-msvc
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-lld --save-toolstates=/tmp/toolstate/toolstates.json
       DEPLOY_TOOLSTATES_JSON: toolstates-windows.json
-    <<: *job-windows-2019-8c
+    <<: *job-windows-8c
 
   # 32/64-bit MinGW builds.
   #
@@ -414,7 +404,7 @@
         --set rust.codegen-units=1
       SCRIPT: python x.py build --set rust.debug=true opt-dist && PGO_HOST=x86_64-pc-windows-msvc ./build/x86_64-pc-windows-msvc/stage0-tools-bin/opt-dist windows-ci -- python x.py dist bootstrap --include-default-paths
       DIST_REQUIRE_ALL_TOOLS: 1
-    <<: *job-windows-2019-8c
+    <<: *job-windows-8c
 
   - image: dist-i686-msvc
     env:
@@ -426,7 +416,7 @@
         --enable-profiler
       SCRIPT: python x.py dist bootstrap --include-default-paths
       DIST_REQUIRE_ALL_TOOLS: 1
-    <<: *job-windows-2019-8c
+    <<: *job-windows-8c
 
   - image: dist-aarch64-msvc
     env:
@@ -437,7 +427,7 @@
         --enable-profiler
       SCRIPT: python x.py dist bootstrap --include-default-paths
       DIST_REQUIRE_ALL_TOOLS: 1
-    <<: *job-windows-2019-8c
+    <<: *job-windows-8c
 
   - image: dist-i686-mingw
     env:
@@ -471,4 +461,4 @@
     env:
       RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-msvc --enable-extended --enable-profiler
       SCRIPT: python x.py dist bootstrap --include-default-paths
-    <<: *job-windows-2019-8c
+    <<: *job-windows-8c
diff --git a/src/ci/scripts/install-clang.sh b/src/ci/scripts/install-clang.sh
index aa7ff81..24b9904 100755
--- a/src/ci/scripts/install-clang.sh
+++ b/src/ci/scripts/install-clang.sh
@@ -10,18 +10,24 @@
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
 # Update both macOS's and Windows's tarballs when bumping the version here.
-LLVM_VERSION="14.0.5"
+# Try to keep this in sync with src/ci/docker/host-x86_64/dist-x86_64-linux/build-clang.sh
+LLVM_VERSION="18.1.4"
 
 if isMacOS; then
+    # FIXME: This is the latest pre-built version of LLVM that's available for
+    # x86_64 MacOS. We may want to consider bulding our own LLVM binaries
+    # instead, or set `USE_XCODE_CLANG` like AArch64 does.
+    LLVM_VERSION="15.0.7"
+
     # If the job selects a specific Xcode version, use that instead of
     # downloading our own version.
     if [[ ${USE_XCODE_CLANG-0} -eq 1 ]]; then
         bindir="$(xcode-select --print-path)/Toolchains/XcodeDefault.xctoolchain/usr/bin"
     else
-        file="${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz"
-        retry curl -f "${file}" -o "clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz"
-        tar xJf "clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin.tar.xz"
-        bindir="$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin/bin"
+        file="${MIRRORS_BASE}/clang%2Bllvm-${LLVM_VERSION}-x86_64-apple-darwin21.0.tar.xz"
+        retry curl -f "${file}" -o "clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin21.0.tar.xz"
+        tar xJf "clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin21.0.tar.xz"
+        bindir="$(pwd)/clang+llvm-${LLVM_VERSION}-x86_64-apple-darwin21.0/bin"
     fi
 
     ciCommandSetEnv CC "${bindir}/clang"
diff --git a/src/doc/book b/src/doc/book
index bebcf52..5e9051f 160000
--- a/src/doc/book
+++ b/src/doc/book
@@ -1 +1 @@
-Subproject commit bebcf527e67755a989a1739b7cfaa8f0e6b30040
+Subproject commit 5e9051f71638aa941cd5dda465e25c61cde9594f
diff --git a/src/doc/embedded-book b/src/doc/embedded-book
index 17842eb..dd962bb 160000
--- a/src/doc/embedded-book
+++ b/src/doc/embedded-book
@@ -1 +1 @@
-Subproject commit 17842ebb050f62e40a4618edeb8e8ee86e758707
+Subproject commit dd962bb82865a5284f2404e5234f1e3222b9c022
diff --git a/src/doc/reference b/src/doc/reference
index 5181795..e356977 160000
--- a/src/doc/reference
+++ b/src/doc/reference
@@ -1 +1 @@
-Subproject commit 51817951d0d213a0011f82b62aae02c3b3f2472e
+Subproject commit e356977fceaa8591c762312d8d446769166d4b3e
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
index 229ad13..2048289 160000
--- a/src/doc/rust-by-example
+++ b/src/doc/rust-by-example
@@ -1 +1 @@
-Subproject commit 229ad13b64d919b12e548d560f06d88963b25cd3
+Subproject commit 20482893d1a502df72f76762c97aed88854cdf81
diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide
index 2d1947f..b6d4a49 160000
--- a/src/doc/rustc-dev-guide
+++ b/src/doc/rustc-dev-guide
@@ -1 +1 @@
-Subproject commit 2d1947ff34d50ca46dfe242ad75531a4c429bb52
+Subproject commit b6d4a4940bab85cc91eec70cc2e3096dd48da62d
diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md
index c9c0ee4..6f81495 100644
--- a/src/doc/rustc/src/SUMMARY.md
+++ b/src/doc/rustc/src/SUMMARY.md
@@ -16,13 +16,17 @@
 - [Platform Support](platform-support.md)
     - [Target Tier Policy](target-tier-policy.md)
     - [Template for Target-specific Documentation](platform-support/TEMPLATE.md)
-    - [arm64e-apple-ios.md](platform-support/arm64e-apple-ios.md)
-    - [arm64e-apple-darwin.md](platform-support/arm64e-apple-darwin.md)
-    - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md)
     - [arm64ec-pc-windows-msvc](platform-support/arm64ec-pc-windows-msvc.md)
+    - [\*-apple-darwin](platform-support/apple-darwin.md)
+        - [i686-apple-darwin](platform-support/i686-apple-darwin.md)
+        - [x86_64h-apple-darwin](platform-support/x86_64h-apple-darwin.md)
+        - [arm64e-apple-darwin.md](platform-support/arm64e-apple-darwin.md)
+    - [\*-apple-ios](platform-support/apple-ios.md)
+        - [\*-apple-ios-macabi](platform-support/apple-ios-macabi.md)
+        - [arm64e-apple-ios.md](platform-support/arm64e-apple-ios.md)
     - [\*-apple-tvos](platform-support/apple-tvos.md)
-    - [\*-apple-watchos\*](platform-support/apple-watchos.md)
-    - [aarch64-apple-visionos\*](platform-support/apple-visionos.md)
+    - [\*-apple-watchos](platform-support/apple-watchos.md)
+    - [\*-apple-visionos](platform-support/apple-visionos.md)
     - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md)
     - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md)
     - [arm-none-eabi](platform-support/arm-none-eabi.md)
@@ -74,8 +78,8 @@
     - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md)
     - [\*-win7-windows-msvc](platform-support/win7-windows-msvc.md)
     - [x86_64-fortanix-unknown-sgx](platform-support/x86_64-fortanix-unknown-sgx.md)
+    - [x86_64-unknown-linux-none.md](platform-support/x86_64-unknown-linux-none.md)
     - [x86_64-unknown-none](platform-support/x86_64-unknown-none.md)
-    - [x86_64h-apple-darwin](platform-support/x86_64h-apple-darwin.md)
 - [Targets](targets/index.md)
     - [Built-in Targets](targets/built-in.md)
     - [Custom Targets](targets/custom.md)
@@ -83,7 +87,8 @@
 - [Profile-guided Optimization](profile-guided-optimization.md)
 - [Instrumentation-based Code Coverage](instrument-coverage.md)
 - [Linker-plugin-based LTO](linker-plugin-lto.md)
-- [Checking conditional configurations](check-cfg.md)
+- [Checking Conditional Configurations](check-cfg.md)
+    - [Cargo Specifics](check-cfg/cargo-specifics.md)
 - [Exploit Mitigations](exploit-mitigations.md)
 - [Symbol Mangling](symbol-mangling/index.md)
     - [v0 Symbol Format](symbol-mangling/v0.md)
diff --git a/src/doc/rustc/src/check-cfg/cargo-specifics.md b/src/doc/rustc/src/check-cfg/cargo-specifics.md
new file mode 100644
index 0000000..bfa6016
--- /dev/null
+++ b/src/doc/rustc/src/check-cfg/cargo-specifics.md
@@ -0,0 +1,73 @@
+# Cargo Specifics - Checking Conditional Configurations
+
+<!--
+This page is currently (as of May 2024) the canonical place for describing the interaction
+between Cargo and --check-cfg. It is placed in the rustc book rather than the Cargo book
+since check-cfg is primarely a Rust/rustc feature and is therefor consider by T-cargo to
+be an implementation detail, at least --check-cfg and the unexpected_cfgs are owned by
+rustc, not Cargo.
+-->
+
+This document is intented to summarize the principal ways Cargo interacts with
+the `unexpected_cfgs` lint and `--check-cfg` flag. It is not intended to provide
+individual details, for that refer to the [`--check-cfg` documentation](../check-cfg.md) and
+to the [Cargo book](../../cargo/index.html).
+
+## Cargo feature
+
+*See the [`[features]` section in the Cargo book][cargo-features] for more details.*
+
+With the `[features]` table Cargo provides a mechanism to express conditional compilation and
+optional dependencies. Cargo *automatically* declares corresponding cfgs for every feature as
+expected.
+
+`Cargo.toml`:
+```toml
+[features]
+serde = ["dep:serde"]
+my_feature = []
+```
+
+[cargo-features]: ../../cargo/reference/features.html
+
+## `check-cfg` in `[lints.rust]` table
+
+<!-- Note that T-Cargo considers `[lints.rust.unexpected_cfgs.check-cfg]` to be an
+implementation detail and is therefor not documented in Cargo, we therefor do that ourself -->
+
+*See the [`[lints]` section in the Cargo book][cargo-lints-table] for more details.*
+
+When using a staticlly known custom config (ie. not dependant on a build-script), Cargo provides
+the custom lint config `check-cfg` under `[lints.rust.unexpected_cfgs]`.
+
+It can be used to set custom static [`--check-cfg`](../check-cfg.md) args, it is mainly useful when
+the list of expected cfgs is known is advance.
+
+`Cargo.toml`:
+```toml
+[lints.rust]
+unexpected_cfgs = { level = "warn", check-cfg = ['cfg(has_foo)'] }
+```
+
+[cargo-lints-table]: ../../cargo/reference/manifest.html#the-lints-section
+
+## `cargo::rustc-check-cfg` for `build.rs`/build-script
+
+*See the [`cargo::rustc-check-cfg` section in the Cargo book][cargo-rustc-check-cfg] for more details.*
+
+When setting a custom config with [`cargo::rustc-cfg`][cargo-rustc-cfg], Cargo provides the
+corollary instruction: [`cargo::rustc-check-cfg`][cargo-rustc-check-cfg] to expect custom configs.
+
+`build.rs`:
+```rust,ignore (cannot-test-this-because-has_foo-isnt-declared)
+fn main() {
+    println!("cargo::rustc-check-cfg=cfg(has_foo)");
+    //        ^^^^^^^^^^^^^^^^^^^^^^ new with Cargo 1.80
+    if has_foo() {
+        println!("cargo::rustc-cfg=has_foo");
+    }
+}
+```
+
+[cargo-rustc-cfg]: ../../cargo/reference/build-scripts.html#rustc-cfg
+[cargo-rustc-check-cfg]: ../../cargo/reference/build-scripts.html#rustc-check-cfg
diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md
index ff80f14..ab95aa2 100644
--- a/src/doc/rustc/src/linker-plugin-lto.md
+++ b/src/doc/rustc/src/linker-plugin-lto.md
@@ -200,6 +200,7 @@
 | 1.60 - 1.64  |      14       |
 | 1.65 - 1.69  |      15       |
 | 1.70 - 1.72  |      16       |
-| 1.73 - 1.74  |      17       |
+| 1.73 - 1.77  |      17       |
+| 1.78         |      18       |
 
 Note that the compatibility policy for this feature might change in the future.
diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md
index 764798a..7785995 100644
--- a/src/doc/rustc/src/platform-support.md
+++ b/src/doc/rustc/src/platform-support.md
@@ -36,7 +36,7 @@
 `i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+) [^x86_32-floats-return-ABI]
 `i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+) [^x86_32-floats-return-ABI]
 `i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+) [^x86_32-floats-return-ABI]
-`x86_64-apple-darwin` | 64-bit macOS (10.12+, Sierra+)
+[`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+)
 `x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 10+)
 `x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+)
 `x86_64-unknown-linux-gnu` | 64-bit Linux (kernel 3.2+, glibc 2.17+)
@@ -86,7 +86,7 @@
 
 target | notes
 -------|-------
-`aarch64-apple-darwin` | ARM64 macOS (11.0+, Big Sur+)
+[`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+)
 `aarch64-pc-windows-msvc` | ARM64 Windows MSVC
 `aarch64-unknown-linux-musl` | ARM64 Linux with musl 1.2.3
 `arm-unknown-linux-gnueabi` | Armv6 Linux (kernel 3.2, glibc 2.17)
@@ -133,8 +133,8 @@
 
 target | std | notes
 -------|:---:|-------
-`aarch64-apple-ios` | ✓ | ARM64 iOS
-[`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ | Apple iOS Simulator on ARM64
+[`aarch64-apple-ios`](platform-support/apple-ios.md) | ✓ | ARM64 iOS
+[`aarch64-apple-ios-sim`](platform-support/apple-ios.md) | ✓ | Apple iOS Simulator on ARM64
 `aarch64-fuchsia` | ✓ | Alias for `aarch64-unknown-fuchsia`
 [`aarch64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | ARM64 Fuchsia
 [`aarch64-linux-android`](platform-support/android.md) | ✓ | ARM64 Android
@@ -192,7 +192,7 @@
 `wasm32-wasi` | ✓ | WebAssembly with WASI (undergoing a [rename to `wasm32-wasip1`][wasi-rename])
 [`wasm32-wasip1`](platform-support/wasm32-wasip1.md) | ✓ | WebAssembly with WASI
 [`wasm32-wasip1-threads`](platform-support/wasm32-wasip1-threads.md) | ✓ |  | WebAssembly with WASI Preview 1 and threads
-`x86_64-apple-ios` | ✓ | 64-bit x86 iOS
+[`x86_64-apple-ios`](platform-support/apple-ios.md) | ✓ | 64-bit x86 iOS
 [`x86_64-fortanix-unknown-sgx`](platform-support/x86_64-fortanix-unknown-sgx.md) | ✓ | [Fortanix ABI] for 64-bit Intel SGX
 `x86_64-fuchsia` | ✓ | Alias for `x86_64-unknown-fuchsia`
 [`x86_64-unknown-fuchsia`](platform-support/fuchsia.md) | ✓ | 64-bit x86 Fuchsia
@@ -241,9 +241,9 @@
 [`arm64e-apple-ios`](platform-support/arm64e-apple-ios.md) | ✓ | | ARM64e Apple iOS
 [`arm64e-apple-darwin`](platform-support/arm64e-apple-darwin.md)  | ✓ | ✓ | ARM64e Apple Darwin
 [`arm64ec-pc-windows-msvc`](platform-support/arm64ec-pc-windows-msvc.md) | ? | | Arm64EC Windows MSVC
-`aarch64-apple-ios-macabi` | ? |  | Apple Catalyst on ARM64
-[`aarch64-apple-tvos`](platform-support/apple-tvos.md) | ? |  | ARM64 tvOS
-[`aarch64-apple-tvos-sim`](platform-support/apple-tvos.md) | ? |  | ARM64 tvOS Simulator
+[`aarch64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ |  | Apple Catalyst on ARM64
+[`aarch64-apple-tvos`](platform-support/apple-tvos.md) | ✓ |  | ARM64 tvOS
+[`aarch64-apple-tvos-sim`](platform-support/apple-tvos.md) | ✓ |  | ARM64 tvOS Simulator
 [`aarch64-apple-watchos`](platform-support/apple-watchos.md) | ✓ |  | ARM64 Apple WatchOS
 [`aarch64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ |  | ARM64 Apple WatchOS Simulator
 [`aarch64-apple-visionos`](platform-support/apple-visionos.md) | ✓ |  | ARM64 Apple visionOS
@@ -283,7 +283,7 @@
 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ |  | ARM SOLID with TOPPERS/ASP3, hardfloat
 [`armv7a-none-eabihf`](platform-support/arm-none-eabi.md) | * |  | Bare Armv7-A, hardfloat
 [`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ |  | Armv7-A Apple WatchOS
-`armv7s-apple-ios` | ✓ |  | Armv7-A Apple-A6 Apple iOS
+[`armv7s-apple-ios`](platform-support/apple-ios.md) | ✓ |  | Armv7-A Apple-A6 Apple iOS
 [`armv8r-none-eabihf`](platform-support/armv8r-none-eabihf.md) | * |  | Bare Armv8-R, hardfloat
 `avr-unknown-gnu-atmega328` | * |  | AVR. Requires `-Z build-std=core`
 `bpfeb-unknown-none` | * |  | BPF (big endian)
@@ -292,10 +292,10 @@
 `csky-unknown-linux-gnuabiv2hf` | ✓ |  | C-SKY abiv2 Linux, hardfloat (little endian)
 [`hexagon-unknown-none-elf`](platform-support/hexagon-unknown-none-elf.md)| * | | Bare Hexagon (v60+, HVX)
 [`hexagon-unknown-linux-musl`](platform-support/hexagon-unknown-linux-musl.md) | ✓ | | Hexagon Linux with musl 1.2.3
-`i386-apple-ios` | ✓ |  | 32-bit x86 iOS [^x86_32-floats-return-ABI]
+[`i386-apple-ios`](platform-support/apple-ios.md) | ✓ |  | 32-bit x86 iOS [^x86_32-floats-return-ABI]
 [`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * |  | 32-bit x86 QNX Neutrino 7.0 RTOS  [^x86_32-floats-return-ABI]
 [`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ |  | 32-bit x86, restricted to Pentium
-`i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+) [^x86_32-floats-return-ABI]
+[`i686-apple-darwin`](platform-support/apple-darwin.md) | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+) [^x86_32-floats-return-ABI]
 `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku [^x86_32-floats-return-ABI]
 [`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd [^x86_32-floats-return-ABI]
 [`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2 [^x86_32-floats-return-ABI]
@@ -367,8 +367,8 @@
 `thumbv7neon-unknown-linux-musleabihf` | ? |  | Thumb2-mode Armv7-A Linux with NEON, musl 1.2.3
 [`wasm32-wasip2`](platform-support/wasm32-wasip2.md) | ✓ |  | WebAssembly
 [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? |  | WebAssembly
-`x86_64-apple-ios-macabi` | ✓ |  | Apple Catalyst on x86_64
-[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? |  | x86 64-bit tvOS
+[`x86_64-apple-ios-macabi`](platform-support/apple-ios-macabi.md) | ✓ |  | Apple Catalyst on x86_64
+[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ✓ |  | x86 64-bit tvOS
 [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ |  | x86 64-bit Apple WatchOS simulator
 [`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ |  | x86 64-bit QNX Neutrino 7.1 RTOS |
 [`x86_64-unikraft-linux-musl`](platform-support/unikraft-linux-musl.md) | ✓ |   | 64-bit Unikraft with musl 1.2.3
@@ -382,5 +382,6 @@
 [`x86_64-win7-windows-msvc`](platform-support/win7-windows-msvc.md) | ✓ |   | 64-bit Windows 7 support
 `x86_64-wrs-vxworks` | ? |  |
 [`x86_64h-apple-darwin`](platform-support/x86_64h-apple-darwin.md) | ✓ | ✓ | macOS with late-gen Intel (at least Haswell)
+[`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * |  | 64-bit Linux with no libc
 
 [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets
diff --git a/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md b/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md
deleted file mode 100644
index 3f29e2c..0000000
--- a/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# aarch64-apple-ios-sim
-
-**Tier: 2**
-
-Apple iOS Simulator on ARM64.
-
-## Designated Developers
-
-* [@badboy](https://github.com/badboy)
-* [@deg4uss3r](https://github.com/deg4uss3r)
-
-## Requirements
-
-This target is cross-compiled.
-To build this target Xcode 12 or higher on macOS is required.
-
-## Building
-
-The target can be built by enabling it for a `rustc` build:
-
-```toml
-[build]
-build-stage = 1
-target = ["aarch64-apple-ios-sim"]
-```
-
-## Cross-compilation
-
-This target can be cross-compiled from `x86_64` or `aarch64` macOS hosts.
-
-Other hosts are not supported for cross-compilation, but might work when also providing the required Xcode SDK.
-
-## Testing
-
-Currently there is no support to run the rustc test suite for this target.
-
-
-## Building Rust programs
-
-*Note: Building for this target requires the corresponding iOS SDK, as provided by Xcode 12+.*
-
-From Rust Nightly 1.56.0 (2021-08-03) on the artifacts are shipped pre-compiled:
-
-```text
-rustup target add aarch64-apple-ios-sim --toolchain nightly
-```
-
-Rust programs can be built for that target:
-
-```text
-rustc --target aarch64-apple-ios-sim your-code.rs
-```
-
-There is no easy way to run simple programs in the iOS simulator.
-Static library builds can be embedded into iOS applications.
diff --git a/src/doc/rustc/src/platform-support/apple-darwin.md b/src/doc/rustc/src/platform-support/apple-darwin.md
new file mode 100644
index 0000000..0fb8694
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/apple-darwin.md
@@ -0,0 +1,59 @@
+# `*-apple-darwin`
+
+Apple macOS targets.
+
+**Tier: 1**
+
+- `x86_64-apple-darwin`: macOS on 64-bit x86.
+
+**Tier: 2 (with Host Tools)**
+
+- `aarch64-apple-darwin`: macOS on ARM64 (M1-family or later Apple Silicon CPUs).
+
+## Target maintainers
+
+- [@thomcc](https://github.com/thomcc)
+- [@madsmtm](https://github.com/madsmtm)
+
+## Requirements
+
+### OS version
+
+The minimum supported version is macOS 10.12 Sierra on x86, and macOS 11.0 Big
+Sur on ARM64.
+
+This version can be raised per-binary by changing the [deployment target],
+which might yield more performance optimizations. `rustc` respects the common
+environment variables used by Xcode to do so, in this case
+`MACOSX_DEPLOYMENT_TARGET`.
+
+The current default deployment target for `rustc` can be retrieved with
+[`rustc --print=deployment-target`][rustc-print].
+
+[deployment target]: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/cross_development/Configuring/configuring.html
+[rustc-print]: ../command-line-arguments.md#option-print
+
+### Binary format
+
+The default binary format is Mach-O, the executable format used on Apple's
+platforms.
+
+## Building
+
+These targets are distributed through `rustup`, and otherwise require no
+special configuration.
+
+## Testing
+
+There are no special requirements for testing and running this target.
+
+x86 binaries can be run on Apple Silicon by using Rosetta.
+
+## Cross-compilation toolchains and C code
+
+Cross-compilation of these targets are supported using Clang, but may require
+Xcode or the macOS SDK (`MacOSX.sdk`) to be available to compile C code and
+to link.
+
+The path to the SDK can be passed to `rustc` using the common `SDKROOT`
+environment variable.
diff --git a/src/doc/rustc/src/platform-support/apple-ios-macabi.md b/src/doc/rustc/src/platform-support/apple-ios-macabi.md
new file mode 100644
index 0000000..278ee94
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/apple-ios-macabi.md
@@ -0,0 +1,58 @@
+# `*-apple-ios-macabi`
+
+Apple Mac Catalyst targets.
+
+**Tier: 3**
+
+- `aarch64-apple-ios-macabi`: Mac Catalyst on ARM64.
+- `x86_64-apple-ios-macabi`: Mac Catalyst on 64-bit x86.
+
+## Target maintainers
+
+- [@madsmtm](https://github.com/madsmtm)
+
+## Requirements
+
+These targets are cross-compiled, and require the corresponding macOS SDK
+(`MacOSX.sdk`) which contain `./System/iOSSupport` headers to allow linking to
+iOS-specific headers, as provided by Xcode 11 or higher.
+
+The path to the SDK can be passed to `rustc` using the common `SDKROOT`
+environment variable.
+
+### OS version
+
+The minimum supported version is iOS 13.1.
+
+This can be raised per-binary by changing the deployment target. `rustc`
+respects the common environment variables used by Xcode to do so, in this
+case `IPHONEOS_DEPLOYMENT_TARGET`.
+
+## Building the target
+
+The targets can be built by enabling them for a `rustc` build in
+`config.toml`, by adding, for example:
+
+```toml
+[build]
+target = ["aarch64-apple-ios-macabi", "x86_64-apple-ios-macabi"]
+```
+
+Using the unstable `-Zbuild-std` with a nightly Cargo may also work.
+
+## Building Rust programs
+
+Rust programs can be built for these targets by specifying `--target`, if
+`rustc` has been built with support for them. For example:
+
+```console
+$ rustc --target aarch64-apple-ios-macabi your-code.rs
+```
+
+## Testing
+
+Mac Catalyst binaries can be run directly on macOS 10.15 Catalina or newer.
+
+x86 binaries can be run on Apple Silicon by using Rosetta.
+
+Note that using certain UIKit functionality requires the binary to be bundled.
diff --git a/src/doc/rustc/src/platform-support/apple-ios.md b/src/doc/rustc/src/platform-support/apple-ios.md
new file mode 100644
index 0000000..5045f81
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/apple-ios.md
@@ -0,0 +1,74 @@
+# `*-apple-ios`
+
+Apple iOS / iPadOS targets.
+
+**Tier: 2 (without Host Tools)**
+
+- `aarch64-apple-ios`: Apple iOS on ARM64.
+- `aarch64-apple-ios-sim`: Apple iOS Simulator on ARM64.
+- `x86_64-apple-ios`: Apple iOS Simulator on 64-bit x86.
+
+**Tier: 3**
+
+- `armv7s-apple-ios`: Apple iOS on Armv7-A.
+- `i386-apple-ios`: Apple iOS Simulator on 32-bit x86.
+
+## Target maintainers
+
+- [@badboy](https://github.com/badboy)
+- [@deg4uss3r](https://github.com/deg4uss3r)
+- [@madsmtm](https://github.com/madsmtm)
+
+## Requirements
+
+These targets are cross-compiled, and require the corresponding iOS SDK
+(`iPhoneOS.sdk` or `iPhoneSimulator.sdk`), as provided by Xcode. To build the
+ARM64 targets, Xcode 12 or higher is required.
+
+The path to the SDK can be passed to `rustc` using the common `SDKROOT`
+environment variable.
+
+### OS version
+
+The minimum supported version is iOS 10.0.
+
+This can be raised per-binary by changing the deployment target. `rustc`
+respects the common environment variables used by Xcode to do so, in this
+case `IPHONEOS_DEPLOYMENT_TARGET`.
+
+## Building the target
+
+The tier 2 targets are distributed through `rustup`, and can be installed
+using one of:
+```console
+$ rustup target add aarch64-apple-ios
+$ rustup target add aarch64-apple-ios-sim
+$ rustup target add x86_64-apple-ios
+```
+
+The tier 3 targets can be built by enabling them for a `rustc` build in
+`config.toml`, by adding, for example:
+
+```toml
+[build]
+target = ["armv7s-apple-ios", "i386-apple-ios"]
+```
+
+Using the unstable `-Zbuild-std` with a nightly Cargo may also work.
+
+## Building Rust programs
+
+Rust programs can be built for these targets by specifying `--target`, if
+`rustc` has been built with support for them. For example:
+
+```console
+$ rustc --target aarch64-apple-ios your-code.rs
+```
+
+## Testing
+
+There is no support for running the Rust or standard library testsuite at the
+moment. Testing has mostly been done manually with builds of static libraries
+embedded into applications called from Xcode or a simulator.
+
+It hopefully will be possible to improve this in the future.
diff --git a/src/doc/rustc/src/platform-support/apple-tvos.md b/src/doc/rustc/src/platform-support/apple-tvos.md
index e7ea109..7a3b601 100644
--- a/src/doc/rustc/src/platform-support/apple-tvos.md
+++ b/src/doc/rustc/src/platform-support/apple-tvos.md
@@ -1,40 +1,44 @@
 # `*-apple-tvos`
-- aarch64-apple-tvos
-- x86_64-apple-tvos
+
+Apple tvOS targets.
 
 **Tier: 3**
 
-Apple tvOS targets:
-- Apple tvOS on aarch64
-- Apple tvOS Simulator on x86_64
+- `aarch64-apple-tvos`: Apple tvOS on ARM64.
+- `aarch64-apple-tvos-sim`: Apple tvOS Simulator on ARM64.
+- `x86_64-apple-tvos`: Apple tvOS Simulator on x86_64.
 
 ## Target maintainers
 
-* [@thomcc](https://github.com/thomcc)
+- [@thomcc](https://github.com/thomcc)
+- [@madsmtm](https://github.com/madsmtm)
 
 ## Requirements
 
-These targets are cross-compiled. You will need appropriate versions of Xcode
-and the SDKs for tvOS (`AppleTVOS.sdk`) and/or the tvOS Simulator
-(`AppleTVSimulator.sdk`) to build a toolchain and target these platforms.
+These targets are cross-compiled, and require the corresponding tvOS SDK
+(`AppleTVOS.sdk` or `AppleTVSimulator.sdk`), as provided by Xcode. To build the
+ARM64 targets, Xcode 12 or higher is required.
 
-The targets support most (see below) of the standard library including the
-allocator to the best of my knowledge, however they are very new, not yet
-well-tested, and it is possible that there are various bugs.
+The path to the SDK can be passed to `rustc` using the common `SDKROOT`
+environment variable.
 
-In theory we support back to tvOS version 7.0, although the actual minimum
-version you can target may be newer than this, for example due to the versions
-of Xcode and your SDKs.
+### OS version
 
-As with the other Apple targets, `rustc` respects the common environment
-variables used by Xcode to configure this, in this case
-`TVOS_DEPLOYMENT_TARGET`.
+The minimum supported version is tvOS 10.0, although the actual minimum version
+you can target may be newer than this, for example due to the versions of Xcode
+and your SDKs.
 
-#### Incompletely supported library functionality
+The version can be raised per-binary by changing the deployment target. `rustc`
+respects the common environment variables used by Xcode to do so, in this
+case `TVOS_DEPLOYMENT_TARGET`.
 
-As mentioned, "most" of the standard library is supported, which means that some portions
-are known to be unsupported. The following APIs are currently known to have
-missing or incomplete support:
+### Incompletely supported library functionality
+
+The targets support most of the standard library including the allocator to the
+best of my knowledge, however they are very new, not yet well-tested, and it is
+possible that there are various bugs.
+
+The following APIs are currently known to have missing or incomplete support:
 
 - `std::process::Command`'s API will return an error if it is configured in a
   manner which cannot be performed using `posix_spawn` -- this is because the
@@ -47,41 +51,30 @@
 
 ## Building the target
 
-The targets can be built by enabling them for a `rustc` build in `config.toml`, by adding, for example:
+The targets can be built by enabling them for a `rustc` build in
+`config.toml`, by adding, for example:
 
 ```toml
 [build]
 build-stage = 1
-target = ["aarch64-apple-tvos", "x86_64-apple-tvos", "aarch64-apple-tvos-sim"]
+target = ["aarch64-apple-tvos", "aarch64-apple-tvos-sim"]
 ```
 
-It's possible that cargo under `-Zbuild-std` may also be used to target them.
+Using the unstable `-Zbuild-std` with a nightly Cargo may also work.
 
 ## Building Rust programs
 
-*Note: Building for this target requires the corresponding TVOS SDK, as provided by Xcode.*
+Rust programs can be built for these targets by specifying `--target`, if
+`rustc` has been built with support for them. For example:
 
-Rust programs can be built for these targets
-
-```text
+```console
 $ rustc --target aarch64-apple-tvos your-code.rs
-...
-$ rustc --target x86_64-apple-tvos your-code.rs
-...
-$ rustc --target aarch64-apple-tvos-sim your-code.rs
 ```
 
 ## Testing
 
-There is no support for running the Rust or standard library testsuite on tvOS
-or the simulators at the moment. Testing has mostly been done manually with
-builds of static libraries called from Xcode or a simulator.
+There is no support for running the Rust or standard library testsuite at the
+moment. Testing has mostly been done manually with builds of static libraries
+embedded into applications called from Xcode or a simulator.
 
 It hopefully will be possible to improve this in the future.
-
-## Cross-compilation toolchains and C code
-
-This target can be cross-compiled from x86_64 or aarch64 macOS hosts.
-
-Other hosts are not supported for cross-compilation, but might work when also
-providing the required Xcode SDK.
diff --git a/src/doc/rustc/src/platform-support/apple-visionos.md b/src/doc/rustc/src/platform-support/apple-visionos.md
index 9874126..56224d7 100644
--- a/src/doc/rustc/src/platform-support/apple-visionos.md
+++ b/src/doc/rustc/src/platform-support/apple-visionos.md
@@ -1,53 +1,67 @@
-# aarch64-apple-visionos\*
+# `*-apple-visionos`
 
--   aarch64-apple-visionos
--   aarch64-apple-visionos-sim
+Apple visionOS / xrOS targets.
 
 **Tier: 3**
 
-Apple visionOS targets:
-
--   Apple visionOS on arm64
--   Apple visionOS Simulator on arm64
+- `aarch64-apple-visionos`: Apple visionOS on arm64.
+- `aarch64-apple-visionos-sim`: Apple visionOS Simulator on arm64.
 
 ## Target maintainers
 
--   [@agg23](https://github.com/agg23)
--   [@madsmtm](https://github.com/madsmtm)
+- [@agg23](https://github.com/agg23)
+- [@madsmtm](https://github.com/madsmtm)
 
 ## Requirements
 
-These targets are cross-compiled.
-To build these targets Xcode 15 or higher on macOS is required, along with LLVM 18.
+These targets are cross-compiled, and require the corresponding visionOS SDK
+(`XROS.sdk` or `XRSimulator.sdk`), as provided by Xcode 15 or newer.
+
+The path to the SDK can be passed to `rustc` using the common `SDKROOT`
+environment variable.
+
+### OS version
+
+The minimum supported version is visionOS 1.0.
+
+This can be raised per-binary by changing the deployment target. `rustc`
+respects the common environment variables used by Xcode to do so, in this
+case `XROS_DEPLOYMENT_TARGET`.
 
 ## Building the target
 
-The targets can be built by enabling them for a `rustc` build, for example:
+The targets can be built by enabling them for a `rustc` build in
+`config.toml`, by adding, for example:
 
 ```toml
 [build]
-build-stage = 1
-target = ["aarch64-apple-visionos-sim"]
+target = ["aarch64-apple-visionos", "aarch64-apple-visionos-sim"]
 ```
 
+Using the unstable `-Zbuild-std` with a nightly Cargo may also work.
+
+Note: Currently, a newer version of `libc` and `cc` may be required, this will
+be fixed in [#124560](https://github.com/rust-lang/rust/pull/124560).
+
 ## Building Rust programs
 
-_Note: Building for this target requires the corresponding visionOS SDK, as provided by Xcode 15+._
+Rust programs can be built for these targets by specifying `--target`, if
+`rustc` has been built with support for them. For example:
 
-Rust programs can be built for these targets, if `rustc` has been built with support for them, for example:
-
-```text
-rustc --target aarch64-apple-visionos-sim your-code.rs
+```console
+$ rustc --target aarch64-apple-visionos-sim your-code.rs
 ```
 
 ## Testing
 
-There is no support for running the Rust testsuite on visionOS or the simulators.
+There is no support for running the Rust or standard library testsuite at the
+moment. Testing has mostly been done manually with builds of static libraries
+embedded into applications called from Xcode or a simulator.
 
-There is no easy way to run simple programs on visionOS or the visionOS simulators. Static library builds can be embedded into visionOS applications.
+It hopefully will be possible to improve this in the future.
 
 ## Cross-compilation toolchains and C code
 
-This target can be cross-compiled from x86_64 or aarch64 macOS hosts.
+The Clang target is suffixed with `-xros` for historical reasons.
 
-Other hosts are not supported for cross-compilation, but might work when also providing the required Xcode SDK.
+LLVM 18 or newer is required to build this target.
diff --git a/src/doc/rustc/src/platform-support/apple-watchos.md b/src/doc/rustc/src/platform-support/apple-watchos.md
index 7be2467..8ba35f7 100644
--- a/src/doc/rustc/src/platform-support/apple-watchos.md
+++ b/src/doc/rustc/src/platform-support/apple-watchos.md
@@ -1,58 +1,65 @@
-# *-apple-watchos
-- arm64_32-apple-watchos
-- armv7k-apple-watchos
-- aarch64-apple-watchos
-- aarch64-apple-watchos-sim
-- x86_64-apple-watchos-sim
+# `*-apple-watchos`
+
+Apple watchOS targets.
 
 **Tier: 3**
 
-Apple WatchOS targets:
-- Apple WatchOS on Arm 64_32
-- Apple WatchOS on Arm v7k
-- Apple WatchOS on Arm 64
-- Apple WatchOS Simulator on arm64
-- Apple WatchOS Simulator on x86_64
+- `aarch64-apple-watchos`: Apple WatchOS on ARM64.
+- `aarch64-apple-watchos-sim`: Apple WatchOS Simulator on ARM64.
+- `x86_64-apple-watchos-sim`: Apple WatchOS Simulator on 64-bit x86.
+- `arm64_32-apple-watchos`: Apple WatchOS on Arm 64_32.
+- `armv7k-apple-watchos`: Apple WatchOS on Armv7k.
 
 ## Target maintainers
 
-* [@deg4uss3r](https://github.com/deg4uss3r)
-* [@vladimir-ea](https://github.com/vladimir-ea)
-* [@leohowell](https://github.com/leohowell)
+- [@deg4uss3r](https://github.com/deg4uss3r)
+- [@vladimir-ea](https://github.com/vladimir-ea)
+- [@leohowell](https://github.com/leohowell)
+- [@madsmtm](https://github.com/madsmtm)
 
 ## Requirements
 
-These targets are cross-compiled.
-To build these targets Xcode 12 or higher on macOS is required.
+These targets are cross-compiled, and require the corresponding watchOS SDK
+(`WatchOS.sdk` or `WatchSimulator.sdk`), as provided by Xcode. To build the
+ARM64 targets, Xcode 12 or higher is required.
+
+The path to the SDK can be passed to `rustc` using the common `SDKROOT`
+environment variable.
+
+### OS version
+
+The minimum supported version is watchOS 5.0.
+
+This can be raised per-binary by changing the deployment target. `rustc`
+respects the common environment variables used by Xcode to do so, in this
+case `WATCHOS_DEPLOYMENT_TARGET`.
 
 ## Building the target
 
-The targets can be built by enabling them for a `rustc` build, for example:
+The targets can be built by enabling them for a `rustc` build in
+`config.toml`, by adding, for example:
 
 ```toml
 [build]
 build-stage = 1
-target = ["aarch64-apple-watchos-sim"]
+target = ["aarch64-apple-watchos", "aarch64-apple-watchos-sim"]
 ```
 
+Using the unstable `-Zbuild-std` with a nightly Cargo may also work.
+
 ## Building Rust programs
 
-*Note: Building for this target requires the corresponding WatchOS SDK, as provided by Xcode 12+.*
+Rust programs can be built for these targets by specifying `--target`, if
+`rustc` has been built with support for them. For example:
 
-Rust programs can be built for these targets, if `rustc` has been built with support for them, for example:
-
-```text
-rustc --target aarch64-apple-watchos-sim your-code.rs
+```console
+$ rustc --target aarch64-apple-watchos-sim your-code.rs
 ```
 
 ## Testing
 
-There is no support for running the Rust testsuite on WatchOS or the simulators.
+There is no support for running the Rust or standard library testsuite at the
+moment. Testing has mostly been done manually with builds of static libraries
+embedded into applications called from Xcode or a simulator.
 
-There is no easy way to run simple programs on WatchOS or the WatchOS simulators. Static library builds can be embedded into WatchOS applications.
-
-## Cross-compilation toolchains and C code
-
-This target can be cross-compiled from x86_64 or aarch64 macOS hosts.
-
-Other hosts are not supported for cross-compilation, but might work when also providing the required Xcode SDK.
+It hopefully will be possible to improve this in the future.
diff --git a/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md b/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md
index d9b9aea..4d98b3a 100644
--- a/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md
+++ b/src/doc/rustc/src/platform-support/arm64e-apple-darwin.md
@@ -12,6 +12,8 @@
 
 Target for `macOS` on late-generation `M` series Apple chips.
 
+See the docs on [`*-apple-darwin`](apple-darwin.md) for general macOS requirements.
+
 ## Building the target
 
 You can build Rust with support for the targets by adding it to the `target` list in `config.toml`:
diff --git a/src/doc/rustc/src/platform-support/arm64e-apple-ios.md b/src/doc/rustc/src/platform-support/arm64e-apple-ios.md
index 0215621..3c878f7 100644
--- a/src/doc/rustc/src/platform-support/arm64e-apple-ios.md
+++ b/src/doc/rustc/src/platform-support/arm64e-apple-ios.md
@@ -10,8 +10,7 @@
 
 ## Requirements
 
-These targets only support cross-compilation.
-The targets do support `std`.
+See the docs on [`*-apple-ios`](apple-ios.md) for general iOS requirements.
 
 ## Building the target
 
diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md
index 9c2e05b..3e1db69 100644
--- a/src/doc/rustc/src/platform-support/fuchsia.md
+++ b/src/doc/rustc/src/platform-support/fuchsia.md
@@ -387,7 +387,7 @@
 ```
 
 *Note: Relative manifest paths are resolved starting from the working directory
-of `pm`. Make sure to fill out `<SDK_PATH>` with the path to the downloaded
+of `ffx`. Make sure to fill out `<SDK_PATH>` with the path to the downloaded
 SDK.*
 
 The `.manifest` file will be used to describe the contents of the package by
@@ -459,12 +459,10 @@
 Next, we'll build a package manifest as defined by our manifest:
 
 ```sh
-${SDK_PATH}/tools/${ARCH}/pm \
-    -api-level $(${SDK_PATH}/tools/${ARCH}/ffx version -v | grep "api-level" | head -1 |  awk -F ' ' '{print $2}') \
-    -o pkg/hello_fuchsia_manifest \
-    -m pkg/hello_fuchsia.manifest \
-    build \
-    -output-package-manifest pkg/hello_fuchsia_package_manifest
+${SDK_PATH}/tools/${ARCH}/ffx package build \
+    --api-level $(${SDK_PATH}/tools/${ARCH}/ffx --machine json version | jq .tool_version.api_level) \
+    --out pkg/hello_fuchsia_manifest \
+    pkg/hello_fuchsia.manifest
 ```
 
 This will produce `pkg/hello_fuchsia_manifest/` which is a package manifest we can
@@ -498,8 +496,7 @@
 We can set up our repository with:
 
 ```sh
-${SDK_PATH}/tools/${ARCH}/pm newrepo \
-    -repo pkg/repo
+${SDK_PATH}/tools/${ARCH}/ffx repository create pkg/repo
 ```
 
 **Current directory structure**
@@ -523,17 +520,17 @@
 We can publish our new package to that repository with:
 
 ```sh
-${SDK_PATH}/tools/${ARCH}/pm publish \
-    -repo pkg/repo \
-    -lp -f <(echo "pkg/hello_fuchsia_package_manifest")
+${SDK_PATH}/tools/${ARCH}/ffx repository publish \
+    --package pkg/hello_fuchsia_package_manifest \
+    pkg/repo
 ```
 
 Then we can add the repository to `ffx`'s package server as `hello-fuchsia` using:
 
 ```sh
 ${SDK_PATH}/tools/${ARCH}/ffx repository add-from-pm \
-    pkg/repo \
-    -r hello-fuchsia
+    --repository hello-fuchsia \
+    pkg/repo
 ```
 
 ## Running a Fuchsia component on an emulator
diff --git a/src/doc/rustc/src/platform-support/i686-apple-darwin.md b/src/doc/rustc/src/platform-support/i686-apple-darwin.md
new file mode 100644
index 0000000..d69fa97
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/i686-apple-darwin.md
@@ -0,0 +1,41 @@
+# `i686-apple-darwin`
+
+Apple macOS on 32-bit x86.
+
+## Target maintainers
+
+- [@thomcc](https://github.com/thomcc)
+- [@madsmtm](https://github.com/madsmtm)
+
+## Requirements
+
+See the docs on [`*-apple-darwin`](apple-darwin.md) for general macOS requirements.
+
+## Building the target
+
+You'll need the macOS 10.13 SDK shipped with Xcode 9. The location of the SDK
+can be passed to `rustc` using the common `SDKROOT` environment variable.
+
+Once you have that, you can build Rust with support for the target by adding
+it to the `target` list in `config.toml`:
+
+```toml
+[build]
+target = ["i686-apple-darwin"]
+```
+
+Using the unstable `-Zbuild-std` with a nightly Cargo may also work.
+
+## Building Rust programs
+
+Rust [no longer] ships pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy using `build-std` or
+similar.
+
+[no longer]: https://blog.rust-lang.org/2020/01/03/reducing-support-for-32-bit-apple-targets.html
+
+## Testing
+
+Running this target requires an Intel Macbook running macOS 10.14 or earlier,
+as later versions removed support for running 32-bit binaries.
diff --git a/src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md b/src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md
new file mode 100644
index 0000000..5608b5c
--- /dev/null
+++ b/src/doc/rustc/src/platform-support/x86_64-unknown-linux-none.md
@@ -0,0 +1,40 @@
+# `x86_64-unknown-linux-none`
+
+**Tier: 3**
+
+Freestanding x86-64 linux binary with no dependency on libc.
+
+## Target maintainers
+
+- [morr0ne](https://github.com/morr0ne/)
+
+## Requirements
+
+This target is cross compiled and can be built from any host.
+
+This target has no support for host tools, std, or alloc.
+
+## Building the target
+
+The target can be built by enabling it for a `rustc` build:
+
+```toml
+[build]
+build-stage = 1
+target = ["x86_64-unknown-linux-none"]
+```
+
+## Building Rust programs
+
+Rust does not yet ship pre-compiled artifacts for this target. To compile for
+this target, you will either need to build Rust with the target enabled (see
+"Building the target" above), or build your own copy of `core` by using
+`build-std` or similar.
+
+## Testing
+
+Created binaries will run on linux without any external requirements
+
+## Cross-compilation toolchains and C code
+
+Support for C code is currently untested
diff --git a/src/doc/rustc/src/platform-support/x86_64h-apple-darwin.md b/src/doc/rustc/src/platform-support/x86_64h-apple-darwin.md
index 0fe9d4e..6c2a6a4 100644
--- a/src/doc/rustc/src/platform-support/x86_64h-apple-darwin.md
+++ b/src/doc/rustc/src/platform-support/x86_64h-apple-darwin.md
@@ -23,9 +23,8 @@
 targeted via cross-compilation (including from `x86_64-apple-darwin`), but if
 built manually, the host tools work.
 
-It is similar to `x86_64-apple-darwin` in nearly all respects, although the
-minimum supported OS version is slightly higher (it requires 10.8 rather than
-`x86_64-apple-darwin`'s 10.7).
+It is similar to [`x86_64-apple-darwin`](apple-darwin.md) in nearly all
+respects.
 
 ## Building the target
 
diff --git a/src/doc/rustc/src/symbol-mangling/v0.md b/src/doc/rustc/src/symbol-mangling/v0.md
index 61f747f..763694a 100644
--- a/src/doc/rustc/src/symbol-mangling/v0.md
+++ b/src/doc/rustc/src/symbol-mangling/v0.md
@@ -739,6 +739,8 @@
   * `z` — `!`
   * `p` — [placeholder] `_`
 
+Remaining primitives are encoded as a crate production, e.g. `C4f128`.
+
 * `A` — An [array][reference-array] `[T; N]`.
 
   > <span id="array-type">array-type</span> → `A` *[type]* *[const]*
diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md
index 822f341..3e104bd 100644
--- a/src/doc/rustdoc/src/command-line-arguments.md
+++ b/src/doc/rustdoc/src/command-line-arguments.md
@@ -273,7 +273,7 @@
 
 When rendering Rust files, this flag is ignored.
 
-## `--html-in-header`: include more HTML in <head>
+## `--html-in-header`: include more HTML in `<head>`
 
 Using this flag looks like this:
 
@@ -417,6 +417,12 @@
 the crate root's docs. You can use this flag to differentiate between different versions of your
 library's documentation.
 
+## `-`: load source code from the standard input
+
+If you specify `-` as the INPUT on the command line, then `rustdoc` will read the
+source code from stdin (standard input stream) until the EOF, instead of the file
+system with an otherwise specified path.
+
 ## `@path`: load command-line flags from a path
 
 If you specify `@path` on the command-line, then it will open `path` and read
diff --git a/src/doc/style-guide/src/editions.md b/src/doc/style-guide/src/editions.md
index b9a89c2..74e873e 100644
--- a/src/doc/style-guide/src/editions.md
+++ b/src/doc/style-guide/src/editions.md
@@ -40,9 +40,12 @@
   of a delimited expression, delimited expressions are generally combinable,
   regardless of the number of members. Previously only applied with exactly
   one member (except for closures with explicit blocks).
+- When line-breaking a binary operator, if the first operand spans multiple
+  lines, use the base indentation of the last line.
 - Miscellaneous `rustfmt` bugfixes.
 - Use version-sort (sort `x8`, `x16`, `x32`, `x64`, `x128` in that order).
 - Change "ASCIIbetical" sort to Unicode-aware "non-lowercase before lowercase".
+- Format single associated type `where` clauses on the same line if they fit.
 
 ## Rust 2015/2018/2021 style edition
 
diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md
index 171a24c..3bb0ee6 100644
--- a/src/doc/style-guide/src/expressions.md
+++ b/src/doc/style-guide/src/expressions.md
@@ -328,6 +328,37 @@
 Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather
 than at other binary operators.
 
+If line-breaking at a binary operator (including assignment operators) where the
+first operand spans multiple lines, use the base indentation of the *last*
+line of the first operand, and indent relative to that:
+
+```rust
+impl SomeType {
+    fn method(&mut self) {
+        self.array[array_index as usize]
+            .as_mut()
+            .expect("thing must exist")
+            .extra_info =
+                long_long_long_long_long_long_long_long_long_long_long_long_long_long_long;
+
+        self.array[array_index as usize]
+            .as_mut()
+            .expect("thing must exist")
+            .extra_info
+                + long_long_long_long_long_long_long_long_long_long_long_long_long_long_long;
+
+        self.array[array_index as usize]
+            .as_mut()
+            .expect("thing must exist")
+            .extra_info = Some(ExtraInfo {
+                parent,
+                count: count as u16,
+                children: children.into_boxed_slice(),
+            });
+    }
+}
+```
+
 ### Casts (`as`)
 
 Format `as` casts like a binary operator. In particular, always include spaces
diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md
index 0066a4b..c062869 100644
--- a/src/doc/style-guide/src/items.md
+++ b/src/doc/style-guide/src/items.md
@@ -295,8 +295,18 @@
 
 These rules apply for `where` clauses on any item.
 
-If immediately following a closing bracket of any kind, write the keyword
-`where` on the same line, with a space before it.
+If a where clause is short, and appears on a short one-line function
+declaration with no body or on a short type with no `=`, format it on
+the same line as the declaration:
+
+```rust
+fn new(&self) -> Self where Self: Sized;
+
+type Item<'a>: SomeTrait where Self: 'a;
+```
+
+Otherwise, if immediately following a closing bracket of any kind, write the
+keyword `where` on the same line, with a space before it.
 
 Otherwise, put `where` on a new line at the same indentation level. Put each
 component of a `where` clause on its own line, block-indented. Use a trailing
@@ -347,7 +357,7 @@
 ```
 
 If a `where` clause is very short, prefer using an inline bound on the type
-parameter.
+parameter if possible.
 
 If a component of a `where` clause does not fit and contains `+`, break it
 before each `+` and block-indent the continuation lines. Put each bound on its
@@ -421,9 +431,21 @@
 bound, put a space after the colon but not before:
 
 ```rust
-pub type Foo: Bar;
+type Foo: Bar;
 ```
 
+If an associated type is short, has no `=`, and has a `where` clause with only
+one entry, format the entire type declaration including the `where` clause on
+the same line if it fits:
+
+```rust
+type Item<'a> where Self: 'a;
+type Item<'a>: PartialEq + Send where Self: 'a;
+```
+
+If the associated type has a `=`, or if the `where` clause contains multiple
+entries, format it across multiple lines as with a type alias.
+
 ## extern items
 
 When writing extern items (such as `extern "C" fn`), always specify the ABI.
diff --git a/src/etc/lldb_lookup.py b/src/etc/lldb_lookup.py
index db3afb0..abbd802 100644
--- a/src/etc/lldb_lookup.py
+++ b/src/etc/lldb_lookup.py
@@ -92,7 +92,7 @@
         return StdVecSyntheticProvider(valobj, dict)
     if rust_type == RustType.STD_VEC_DEQUE:
         return StdVecDequeSyntheticProvider(valobj, dict)
-    if rust_type == RustType.STD_SLICE:
+    if rust_type == RustType.STD_SLICE or rust_type == RustType.STD_STR:
         return StdSliceSyntheticProvider(valobj, dict)
 
     if rust_type == RustType.STD_HASH_MAP:
diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py
index a87fd60..c633011 100644
--- a/src/etc/lldb_providers.py
+++ b/src/etc/lldb_providers.py
@@ -159,6 +159,9 @@
     # logger = Logger.Logger()
     # logger >> "[StdStrSummaryProvider] for " + str(valobj.GetName())
 
+    # the code below assumes non-synthetic value, this makes sure the assumption holds
+    valobj = valobj.GetNonSyntheticValue()
+
     length = valobj.GetChildMemberWithName("length").GetValueAsUnsigned()
     if length == 0:
         return '""'
diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs
index daf6399..bccad29 100644
--- a/src/librustdoc/clean/auto_trait.rs
+++ b/src/librustdoc/clean/auto_trait.rs
@@ -119,7 +119,7 @@
         attrs: Default::default(),
         item_id: clean::ItemId::Auto { trait_: trait_def_id, for_: item_def_id },
         kind: Box::new(clean::ImplItem(Box::new(clean::Impl {
-            unsafety: hir::Unsafety::Normal,
+            safety: hir::Safety::Safe,
             generics,
             trait_: Some(clean_trait_ref_with_bindings(cx, trait_ref, ThinVec::new())),
             for_: clean_middle_ty(ty::Binder::dummy(ty), cx, None, None),
@@ -150,7 +150,7 @@
     let generics = tcx.generics_of(item_def_id);
 
     let params: ThinVec<_> = generics
-        .params
+        .own_params
         .iter()
         .inspect(|param| {
             if cfg!(debug_assertions) {
@@ -326,7 +326,7 @@
     }
 
     let region_params: FxIndexSet<_> = generics
-        .params
+        .own_params
         .iter()
         .filter_map(|param| match param.kind {
             ty::GenericParamDefKind::Lifetime => Some(param.name),
diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs
index 8ed6ee0..29be3a7 100644
--- a/src/librustdoc/clean/blanket_impl.rs
+++ b/src/librustdoc/clean/blanket_impl.rs
@@ -1,7 +1,7 @@
 use rustc_hir as hir;
 use rustc_infer::infer::{DefineOpaqueTypes, InferOk, TyCtxtInferExt};
 use rustc_infer::traits;
-use rustc_middle::ty::{self, ToPredicate};
+use rustc_middle::ty::{self, Upcast};
 use rustc_span::def_id::DefId;
 use rustc_span::DUMMY_SP;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
@@ -64,7 +64,7 @@
                 .instantiate(tcx, impl_args)
                 .predicates
                 .into_iter()
-                .chain(Some(ty::Binder::dummy(impl_trait_ref).to_predicate(tcx)));
+                .chain(Some(impl_trait_ref.upcast(tcx)));
             for predicate in predicates {
                 let obligation = traits::Obligation::new(
                     tcx,
@@ -87,7 +87,7 @@
                 attrs: Default::default(),
                 item_id: clean::ItemId::Blanket { impl_id: impl_def_id, for_: item_def_id },
                 kind: Box::new(clean::ImplItem(Box::new(clean::Impl {
-                    unsafety: hir::Unsafety::Normal,
+                    safety: hir::Safety::Safe,
                     generics: clean_ty_generics(
                         cx,
                         tcx.generics_of(impl_def_id),
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 4d506ed..2919a4c 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -14,6 +14,7 @@
 use rustc_metadata::creader::{CStore, LoadedMacro};
 use rustc_middle::ty::fast_reject::SimplifiedType;
 use rustc_middle::ty::{self, TyCtxt};
+use rustc_span::def_id::LOCAL_CRATE;
 use rustc_span::hygiene::MacroKind;
 use rustc_span::symbol::{kw, sym, Symbol};
 
@@ -444,24 +445,24 @@
 
     let associated_trait = tcx.impl_trait_ref(did).map(ty::EarlyBinder::skip_binder);
 
+    // Do not inline compiler-internal items unless we're a compiler-internal crate.
+    let is_compiler_internal = |did| {
+        tcx.lookup_stability(did)
+            .is_some_and(|stab| stab.is_unstable() && stab.feature == sym::rustc_private)
+    };
+    let document_compiler_internal = is_compiler_internal(LOCAL_CRATE.as_def_id());
+    let is_directly_public = |cx: &mut DocContext<'_>, did| {
+        cx.cache.effective_visibilities.is_directly_public(tcx, did)
+            && (document_compiler_internal || !is_compiler_internal(did))
+    };
+
     // Only inline impl if the implemented trait is
     // reachable in rustdoc generated documentation
     if !did.is_local()
         && let Some(traitref) = associated_trait
+        && !is_directly_public(cx, traitref.def_id)
     {
-        let did = traitref.def_id;
-        if !cx.cache.effective_visibilities.is_directly_public(tcx, did) {
-            return;
-        }
-
-        if !tcx.features().rustc_private && !cx.render_options.force_unstable_if_unmarked {
-            if let Some(stab) = tcx.lookup_stability(did)
-                && stab.is_unstable()
-                && stab.feature == sym::rustc_private
-            {
-                return;
-            }
-        }
+        return;
     }
 
     let impl_item = match did.as_local() {
@@ -484,21 +485,11 @@
 
     // Only inline impl if the implementing type is
     // reachable in rustdoc generated documentation
-    if !did.is_local() {
-        if let Some(did) = for_.def_id(&cx.cache) {
-            if !cx.cache.effective_visibilities.is_directly_public(tcx, did) {
-                return;
-            }
-
-            if !tcx.features().rustc_private && !cx.render_options.force_unstable_if_unmarked {
-                if let Some(stab) = tcx.lookup_stability(did)
-                    && stab.is_unstable()
-                    && stab.feature == sym::rustc_private
-                {
-                    return;
-                }
-            }
-        }
+    if !did.is_local()
+        && let Some(did) = for_.def_id(&cx.cache)
+        && !is_directly_public(cx, did)
+    {
+        return;
     }
 
     let document_hidden = cx.render_options.document_hidden;
@@ -622,7 +613,7 @@
         did,
         None,
         clean::ImplItem(Box::new(clean::Impl {
-            unsafety: hir::Unsafety::Normal,
+            safety: hir::Safety::Safe,
             generics,
             trait_,
             for_,
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index f437c7d..73737da 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -453,7 +453,15 @@
     cx: &mut DocContext<'tcx>,
 ) -> WherePredicate {
     WherePredicate::EqPredicate {
-        lhs: clean_projection(pred.map_bound(|p| p.projection_ty), cx, None),
+        lhs: clean_projection(
+            pred.map_bound(|p| {
+                // FIXME: This needs to be made resilient for `AliasTerm`s that
+                // are associated consts.
+                p.projection_term.expect_ty(cx.tcx)
+            }),
+            cx,
+            None,
+        ),
         rhs: clean_middle_term(pred.map_bound(|p| p.term), cx),
     }
 }
@@ -795,7 +803,7 @@
     let mut impl_trait = BTreeMap::<u32, Vec<GenericBound>>::default();
 
     let params: ThinVec<_> = gens
-        .params
+        .own_params
         .iter()
         .filter(|param| match param.kind {
             ty::GenericParamDefKind::Lifetime => !param.is_anonymous_lifetime(),
@@ -838,7 +846,7 @@
                         }
                     }
                     ty::ClauseKind::Projection(p) => {
-                        if let ty::Param(param) = p.projection_ty.self_ty().kind() {
+                        if let ty::Param(param) = p.projection_term.self_ty().kind() {
                             projection = Some(bound_p.rebind(p));
                             return Some(param.index);
                         }
@@ -857,7 +865,15 @@
                 bounds.extend(pred.get_bounds().into_iter().flatten().cloned());
 
                 if let Some(proj) = projection
-                    && let lhs = clean_projection(proj.map_bound(|p| p.projection_ty), cx, None)
+                    && let lhs = clean_projection(
+                        proj.map_bound(|p| {
+                            // FIXME: This needs to be made resilient for `AliasTerm`s that
+                            // are associated consts.
+                            p.projection_term.expect_ty(cx.tcx)
+                        }),
+                        cx,
+                        None,
+                    )
                     && let Some((_, trait_did, name)) = lhs.projection()
                 {
                     impl_trait_proj.entry(param_idx).or_default().push((
@@ -1860,9 +1876,9 @@
         return None;
     }
 
-    use crate::rustc_trait_selection::infer::TyCtxtInferExt;
-    use crate::rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
     use rustc_middle::traits::ObligationCause;
+    use rustc_trait_selection::infer::TyCtxtInferExt;
+    use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 
     // Try to normalize `<X as Y>::T` to a type
     let infcx = cx.tcx.infer_ctxt().build();
@@ -1988,7 +2004,7 @@
                 let generics = tcx.generics_of(container);
                 debug_assert_eq!(generics.parent_count, 0);
 
-                let param = generics.params[index].def_id;
+                let param = generics.own_params[index].def_id;
                 let default = tcx.object_lifetime_default(param);
                 match default {
                     rbv::ObjectLifetimeDefault::Param(lifetime) => {
@@ -2061,7 +2077,7 @@
             let generic_params = clean_bound_vars(sig.bound_vars());
 
             BareFunction(Box::new(BareFunctionDecl {
-                unsafety: sig.unsafety(),
+                safety: sig.safety(),
                 generic_params,
                 decl,
                 abi: sig.abi(),
@@ -2126,7 +2142,10 @@
                                 // HACK(compiler-errors): Doesn't actually matter what self
                                 // type we put here, because we're only using the GAT's args.
                                 .with_self_ty(cx.tcx, cx.tcx.types.self_param)
-                                .projection_ty
+                                .projection_term
+                                // FIXME: This needs to be made resilient for `AliasTerm`s
+                                // that are associated consts.
+                                .expect_ty(cx.tcx)
                         }),
                         cx,
                     ),
@@ -2284,10 +2303,12 @@
                 .iter()
                 .filter_map(|bound| {
                     if let ty::ClauseKind::Projection(proj) = bound.kind().skip_binder() {
-                        if proj.projection_ty.trait_ref(cx.tcx) == trait_ref.skip_binder() {
+                        if proj.projection_term.trait_ref(cx.tcx) == trait_ref.skip_binder() {
                             Some(TypeBinding {
                                 assoc: projection_to_path_segment(
-                                    bound.kind().rebind(proj.projection_ty),
+                                    // FIXME: This needs to be made resilient for `AliasTerm`s that
+                                    // are associated consts.
+                                    bound.kind().rebind(proj.projection_term.expect_ty(cx.tcx)),
                                     cx,
                                 ),
                                 kind: TypeBindingKind::Equality {
@@ -2544,7 +2565,7 @@
         let decl = clean_fn_decl_with_args(cx, bare_fn.decl, None, args);
         (generic_params, decl)
     });
-    BareFunctionDecl { unsafety: bare_fn.unsafety, abi: bare_fn.abi, decl, generic_params }
+    BareFunctionDecl { safety: bare_fn.safety, abi: bare_fn.abi, decl, generic_params }
 }
 
 pub(crate) fn reexport_chain<'tcx>(
@@ -2853,7 +2874,7 @@
         });
     let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| {
         let kind = ImplItem(Box::new(Impl {
-            unsafety: impl_.unsafety,
+            safety: impl_.safety,
             generics: clean_generics(impl_.generics, cx),
             trait_,
             for_,
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index af81cc6..b54ec62 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -636,17 +636,17 @@
                 ty::Asyncness::Yes => hir::IsAsync::Async(DUMMY_SP),
                 ty::Asyncness::No => hir::IsAsync::NotAsync,
             };
-            hir::FnHeader { unsafety: sig.unsafety(), abi: sig.abi(), constness, asyncness }
+            hir::FnHeader { safety: sig.safety(), abi: sig.abi(), constness, asyncness }
         }
         let header = match *self.kind {
             ItemKind::ForeignFunctionItem(_) => {
                 let def_id = self.def_id().unwrap();
                 let abi = tcx.fn_sig(def_id).skip_binder().abi();
                 hir::FnHeader {
-                    unsafety: if abi == Abi::RustIntrinsic {
+                    safety: if abi == Abi::RustIntrinsic {
                         intrinsic_operation_unsafety(tcx, def_id.expect_local())
                     } else {
-                        hir::Unsafety::Unsafe
+                        hir::Safety::Unsafe
                     },
                     abi,
                     constness: if abi == Abi::RustIntrinsic
@@ -1448,8 +1448,8 @@
     pub(crate) fn is_notable_trait(&self, tcx: TyCtxt<'_>) -> bool {
         tcx.is_doc_notable_trait(self.def_id)
     }
-    pub(crate) fn unsafety(&self, tcx: TyCtxt<'_>) -> hir::Unsafety {
-        tcx.trait_def(self.def_id).unsafety
+    pub(crate) fn safety(&self, tcx: TyCtxt<'_>) -> hir::Safety {
+        tcx.trait_def(self.def_id).safety
     }
     pub(crate) fn is_object_safe(&self, tcx: TyCtxt<'_>) -> bool {
         tcx.check_is_object_safe(self.def_id)
@@ -2344,7 +2344,7 @@
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub(crate) struct BareFunctionDecl {
-    pub(crate) unsafety: hir::Unsafety,
+    pub(crate) safety: hir::Safety,
     pub(crate) generic_params: Vec<GenericParamDef>,
     pub(crate) decl: FnDecl,
     pub(crate) abi: Abi,
@@ -2446,7 +2446,7 @@
 
 #[derive(Clone, Debug)]
 pub(crate) struct Impl {
-    pub(crate) unsafety: hir::Unsafety,
+    pub(crate) safety: hir::Safety,
     pub(crate) generics: Generics,
     pub(crate) trait_: Option<Path>,
     pub(crate) for_: Type,
diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs
index 465f969..012afad 100644
--- a/src/librustdoc/config.rs
+++ b/src/librustdoc/config.rs
@@ -1,6 +1,9 @@
 use std::collections::BTreeMap;
 use std::ffi::OsStr;
 use std::fmt;
+use std::io;
+use std::io::Read;
+use std::path::Path;
 use std::path::PathBuf;
 use std::str::FromStr;
 
@@ -9,14 +12,14 @@
     self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType,
 };
 use rustc_session::config::{get_cmd_lint_options, nightly_options};
-use rustc_session::config::{
-    CodegenOptions, ErrorOutputType, Externs, JsonUnusedExterns, UnstableOptions,
-};
+use rustc_session::config::{CodegenOptions, ErrorOutputType, Externs, Input};
+use rustc_session::config::{JsonUnusedExterns, UnstableOptions};
 use rustc_session::getopts;
 use rustc_session::lint::Level;
 use rustc_session::search_paths::SearchPath;
 use rustc_session::EarlyDiagCtxt;
 use rustc_span::edition::Edition;
+use rustc_span::FileName;
 use rustc_target::spec::TargetTriple;
 
 use crate::core::new_dcx;
@@ -60,7 +63,7 @@
 pub(crate) struct Options {
     // Basic options / Options passed directly to rustc
     /// The crate root or Markdown file to load.
-    pub(crate) input: PathBuf,
+    pub(crate) input: Input,
     /// The name of the crate being documented.
     pub(crate) crate_name: Option<String>,
     /// Whether or not this is a bin crate
@@ -179,7 +182,7 @@
         }
 
         f.debug_struct("Options")
-            .field("input", &self.input)
+            .field("input", &self.input.source_name())
             .field("crate_name", &self.crate_name)
             .field("bin_crate", &self.bin_crate)
             .field("proc_macro_crate", &self.proc_macro_crate)
@@ -285,8 +288,6 @@
     pub(crate) no_emit_shared: bool,
     /// If `true`, HTML source code pages won't be generated.
     pub(crate) html_no_source: bool,
-    /// Whether `-Zforce-unstable-if-unmarked` unstable option is set
-    pub(crate) force_unstable_if_unmarked: bool,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -322,6 +323,23 @@
     }
 }
 
+/// Create the input (string or file path)
+///
+/// Warning: Return an unrecoverable error in case of error!
+fn make_input(early_dcx: &EarlyDiagCtxt, input: &str) -> Input {
+    if input == "-" {
+        let mut src = String::new();
+        if io::stdin().read_to_string(&mut src).is_err() {
+            // Immediately stop compilation if there was an issue reading
+            // the input (for example if the input stream is not UTF-8).
+            early_dcx.early_fatal("couldn't read from stdin, as it did not contain valid UTF-8");
+        }
+        Input::Str { name: FileName::anon_source_code(&src), input: src }
+    } else {
+        Input::File(PathBuf::from(input))
+    }
+}
+
 impl Options {
     /// Parses the given command-line for options. If an error message or other early-return has
     /// been printed, returns `Err` with the exit code.
@@ -353,7 +371,6 @@
 
         let codegen_options = CodegenOptions::build(early_dcx, matches);
         let unstable_opts = UnstableOptions::build(early_dcx, matches);
-        let force_unstable_if_unmarked = unstable_opts.force_unstable_if_unmarked;
 
         let dcx = new_dcx(error_format, None, diagnostic_width, &unstable_opts);
 
@@ -450,15 +467,16 @@
 
         let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(early_dcx, matches);
 
-        let input = PathBuf::from(if describe_lints {
+        let input = if describe_lints {
             "" // dummy, this won't be used
-        } else if matches.free.is_empty() {
-            dcx.fatal("missing file operand");
-        } else if matches.free.len() > 1 {
-            dcx.fatal("too many file operands");
         } else {
-            &matches.free[0]
-        });
+            match matches.free.as_slice() {
+                [] => dcx.fatal("missing file operand"),
+                [input] => input,
+                _ => dcx.fatal("too many file operands"),
+            }
+        };
+        let input = make_input(early_dcx, &input);
 
         let externs = parse_externs(early_dcx, matches, &unstable_opts);
         let extern_html_root_urls = match parse_extern_html_roots(matches) {
@@ -790,14 +808,15 @@
             call_locations,
             no_emit_shared: false,
             html_no_source,
-            force_unstable_if_unmarked,
         };
         Some((options, render_options))
     }
 
     /// Returns `true` if the file given as `self.input` is a Markdown file.
-    pub(crate) fn markdown_input(&self) -> bool {
-        self.input.extension().is_some_and(|e| e == "md" || e == "markdown")
+    pub(crate) fn markdown_input(&self) -> Option<&Path> {
+        self.input
+            .opt_path()
+            .filter(|p| matches!(p.extension(), Some(e) if e == "md" || e == "markdown"))
     }
 }
 
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 25b78d9..feb03b9 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -32,7 +32,7 @@
 use crate::formats::cache::Cache;
 use crate::passes::{self, Condition::*};
 
-pub(crate) use rustc_session::config::{Input, Options, UnstableOptions};
+pub(crate) use rustc_session::config::{Options, UnstableOptions};
 
 pub(crate) struct DocContext<'tcx> {
     pub(crate) tcx: TyCtxt<'tcx>,
@@ -204,8 +204,6 @@
     // Add the doc cfg into the doc build.
     cfgs.push("doc".to_string());
 
-    let input = Input::File(input);
-
     // By default, rustdoc ignores all lints.
     // Specifically unblock lints relevant to documentation or the lint machinery itself.
     let mut lints_to_show = vec![
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 0ad4c9c..82f9cf1 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -93,8 +93,6 @@
     dcx: &rustc_errors::DiagCtxt,
     options: RustdocOptions,
 ) -> Result<(), ErrorGuaranteed> {
-    let input = config::Input::File(options.input.clone());
-
     let invalid_codeblock_attributes_name = crate::lint::INVALID_CODEBLOCK_ATTRIBUTES.name;
 
     // See core::create_config for what's going on here.
@@ -140,7 +138,7 @@
         opts: sessopts,
         crate_cfg: cfgs,
         crate_check_cfg: options.check_cfgs.clone(),
-        input,
+        input: options.input.clone(),
         output_file: None,
         output_dir: None,
         file_loader: None,
@@ -686,9 +684,9 @@
                     }
                 }
 
-                // The supplied slice is only used for diagnostics,
+                // The supplied item is only used for diagnostics,
                 // which are swallowed here anyway.
-                parser.maybe_consume_incorrect_semicolon(&[]);
+                parser.maybe_consume_incorrect_semicolon(None);
             }
 
             // Reset errors so that they won't be reported as compiler bugs when dropping the
diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs
index 57e82b8..6beca8b 100644
--- a/src/librustdoc/externalfiles.rs
+++ b/src/librustdoc/externalfiles.rs
@@ -1,5 +1,5 @@
 use crate::html::markdown::{ErrorCodes, HeadingOffset, IdMap, Markdown, Playground};
-use crate::rustc_span::edition::Edition;
+use rustc_span::edition::Edition;
 use std::fs;
 use std::path::Path;
 use std::str;
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index f82b89f..587c464 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -594,9 +594,9 @@
     root_path: Option<&str>,
     original_def_kind: DefKind,
 ) -> Result<(String, ItemType, Vec<Symbol>), HrefError> {
-    use crate::rustc_trait_selection::infer::TyCtxtInferExt;
-    use crate::rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
     use rustc_middle::traits::ObligationCause;
+    use rustc_trait_selection::infer::TyCtxtInferExt;
+    use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
 
     let tcx = cx.tcx();
     let crate_name = tcx.crate_name(def_id.krate);
@@ -1013,7 +1013,7 @@
         }
         clean::BareFunction(ref decl) => {
             print_higher_ranked_params_with_space(&decl.generic_params, cx).fmt(f)?;
-            decl.unsafety.print_with_space().fmt(f)?;
+            decl.safety.print_with_space().fmt(f)?;
             print_abi_with_space(decl.abi).fmt(f)?;
             if f.alternate() {
                 f.write_str("fn")?;
@@ -1303,7 +1303,7 @@
                 // Link should match `# Trait implementations`
 
                 print_higher_ranked_params_with_space(&bare_fn.generic_params, cx).fmt(f)?;
-                bare_fn.unsafety.print_with_space().fmt(f)?;
+                bare_fn.safety.print_with_space().fmt(f)?;
                 print_abi_with_space(bare_fn.abi).fmt(f)?;
                 let ellipsis = if bare_fn.decl.c_variadic { ", ..." } else { "" };
                 primitive_link_fragment(
@@ -1604,11 +1604,11 @@
     fn print_with_space(&self) -> &str;
 }
 
-impl PrintWithSpace for hir::Unsafety {
+impl PrintWithSpace for hir::Safety {
     fn print_with_space(&self) -> &str {
         match self {
-            hir::Unsafety::Unsafe => "unsafe ",
-            hir::Unsafety::Normal => "",
+            hir::Safety::Unsafe => "unsafe ",
+            hir::Safety::Safe => "",
         }
     }
 }
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 075d94b..f3ae4b7 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -52,6 +52,7 @@
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_hir::def_id::{DefId, DefIdSet};
 use rustc_hir::Mutability;
+use rustc_middle::ty::print::PrintTraitRefExt;
 use rustc_middle::ty::{self, TyCtxt};
 use rustc_session::RustcVersion;
 use rustc_span::{
@@ -933,7 +934,7 @@
         RenderMode::ForDeref { .. } => "",
     };
     let asyncness = header.asyncness.print_with_space();
-    let unsafety = header.unsafety.print_with_space();
+    let safety = header.safety.print_with_space();
     let abi = print_abi_with_space(header.abi).to_string();
     let href = assoc_href_attr(meth, link, cx);
 
@@ -944,7 +945,7 @@
         + defaultness.len()
         + constness.len()
         + asyncness.len()
-        + unsafety.len()
+        + safety.len()
         + abi.len()
         + name.as_str().len()
         + generics_len;
@@ -963,14 +964,14 @@
     w.reserve(header_len + "<a href=\"\" class=\"fn\">{".len() + "</a>".len());
     write!(
         w,
-        "{indent}{vis}{defaultness}{constness}{asyncness}{unsafety}{abi}fn \
+        "{indent}{vis}{defaultness}{constness}{asyncness}{safety}{abi}fn \
          <a{href} class=\"fn\">{name}</a>{generics}{decl}{notable_traits}{where_clause}",
         indent = indent_str,
         vis = vis,
         defaultness = defaultness,
         constness = constness,
         asyncness = asyncness,
-        unsafety = unsafety,
+        safety = safety,
         abi = abi,
         href = href,
         name = name,
@@ -1423,6 +1424,10 @@
     if let Some(impls) = cx.cache().impls.get(&did) {
         for i in impls {
             let impl_ = i.inner_impl();
+            if impl_.polarity != ty::ImplPolarity::Positive {
+                continue;
+            }
+
             if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) {
                 // Two different types might have the same did,
                 // without actually being the same.
@@ -1458,6 +1463,10 @@
 
     for i in impls {
         let impl_ = i.inner_impl();
+        if impl_.polarity != ty::ImplPolarity::Positive {
+            continue;
+        }
+
         if !ty.is_doc_subtype_of(&impl_.for_, cx.cache()) {
             // Two different types might have the same did,
             // without actually being the same.
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 7de2aea..c7a23aa 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -492,7 +492,7 @@
 
                 let unsafety_flag = match *myitem.kind {
                     clean::FunctionItem(_) | clean::ForeignFunctionItem(_)
-                        if myitem.fn_header(tcx).unwrap().unsafety == hir::Unsafety::Unsafe =>
+                        if myitem.fn_header(tcx).unwrap().safety == hir::Safety::Unsafe =>
                     {
                         "<sup title=\"unsafe function\">⚠</sup>"
                     }
@@ -616,7 +616,7 @@
     let tcx = cx.tcx();
     let header = it.fn_header(tcx).expect("printing a function which isn't a function");
     let constness = print_constness_with_space(&header.constness, it.const_stability(tcx));
-    let unsafety = header.unsafety.print_with_space();
+    let safety = header.safety.print_with_space();
     let abi = print_abi_with_space(header.abi).to_string();
     let asyncness = header.asyncness.print_with_space();
     let visibility = visibility_print_with_space(it, cx).to_string();
@@ -627,7 +627,7 @@
         + visibility.len()
         + constness.len()
         + asyncness.len()
-        + unsafety.len()
+        + safety.len()
         + abi.len()
         + name.as_str().len()
         + generics_len;
@@ -638,13 +638,13 @@
         w.reserve(header_len);
         write!(
             w,
-            "{attrs}{vis}{constness}{asyncness}{unsafety}{abi}fn \
+            "{attrs}{vis}{constness}{asyncness}{safety}{abi}fn \
                 {name}{generics}{decl}{notable_traits}{where_clause}",
             attrs = render_attributes_in_pre(it, "", cx),
             vis = visibility,
             constness = constness,
             asyncness = asyncness,
-            unsafety = unsafety,
+            safety = safety,
             abi = abi,
             name = name,
             generics = f.generics.print(cx),
@@ -674,10 +674,10 @@
     wrap_item(w, |mut w| {
         write!(
             w,
-            "{attrs}{vis}{unsafety}{is_auto}trait {name}{generics}{bounds}",
+            "{attrs}{vis}{safety}{is_auto}trait {name}{generics}{bounds}",
             attrs = render_attributes_in_pre(it, "", cx),
             vis = visibility_print_with_space(it, cx),
-            unsafety = t.unsafety(tcx).print_with_space(),
+            safety = t.safety(tcx).print_with_space(),
             is_auto = if t.is_auto(tcx) { "auto " } else { "" },
             name = it.name.unwrap(),
             generics = t.generics.print(cx),
diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs
index 35b99ab..f856b4e 100644
--- a/src/librustdoc/json/conversions.rs
+++ b/src/librustdoc/json/conversions.rs
@@ -619,10 +619,10 @@
 
 impl FromWithTcx<clean::BareFunctionDecl> for FunctionPointer {
     fn from_tcx(bare_decl: clean::BareFunctionDecl, tcx: TyCtxt<'_>) -> Self {
-        let clean::BareFunctionDecl { unsafety, generic_params, decl, abi } = bare_decl;
+        let clean::BareFunctionDecl { safety, generic_params, decl, abi } = bare_decl;
         FunctionPointer {
             header: Header {
-                unsafe_: matches!(unsafety, rustc_hir::Unsafety::Unsafe),
+                unsafe_: matches!(safety, rustc_hir::Safety::Unsafe),
                 const_: false,
                 async_: false,
                 abi: convert_abi(abi),
@@ -651,7 +651,7 @@
 impl FromWithTcx<clean::Trait> for Trait {
     fn from_tcx(trait_: clean::Trait, tcx: TyCtxt<'_>) -> Self {
         let is_auto = trait_.is_auto(tcx);
-        let is_unsafe = trait_.unsafety(tcx) == rustc_hir::Unsafety::Unsafe;
+        let is_unsafe = trait_.safety(tcx) == rustc_hir::Safety::Unsafe;
         let is_object_safe = trait_.is_object_safe(tcx);
         let clean::Trait { items, generics, bounds, .. } = trait_;
         Trait {
@@ -678,7 +678,7 @@
 impl FromWithTcx<clean::Impl> for Impl {
     fn from_tcx(impl_: clean::Impl, tcx: TyCtxt<'_>) -> Self {
         let provided_trait_methods = impl_.provided_trait_methods(tcx);
-        let clean::Impl { unsafety, generics, trait_, for_, items, polarity, kind } = impl_;
+        let clean::Impl { safety, generics, trait_, for_, items, polarity, kind } = impl_;
         // FIXME: use something like ImplKind in JSON?
         let (synthetic, blanket_impl) = match kind {
             clean::ImplKind::Normal | clean::ImplKind::FakeVariadic => (false, None),
@@ -690,7 +690,7 @@
             ty::ImplPolarity::Negative => true,
         };
         Impl {
-            is_unsafe: unsafety == rustc_hir::Unsafety::Unsafe,
+            is_unsafe: safety == rustc_hir::Safety::Unsafe,
             generics: generics.into_tcx(tcx),
             provided_trait_methods: provided_trait_methods
                 .into_iter()
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index f2a7518..0650afb 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -730,10 +730,10 @@
         core::new_dcx(options.error_format, None, options.diagnostic_width, &options.unstable_opts);
 
     match (options.should_test, options.markdown_input()) {
-        (true, true) => return wrap_return(&diag, markdown::test(options)),
-        (true, false) => return doctest::run(&diag, options),
-        (false, true) => {
-            let input = options.input.clone();
+        (true, Some(_)) => return wrap_return(&diag, markdown::test(options)),
+        (true, None) => return doctest::run(&diag, options),
+        (false, Some(input)) => {
+            let input = input.to_owned();
             let edition = options.edition;
             let config = core::create_config(options, &render_options, using_internal_features);
 
@@ -747,7 +747,7 @@
                 }),
             );
         }
-        (false, false) => {}
+        (false, None) => {}
     }
 
     // need to move these items separately because we lose them by the time the closure is called,
diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs
index dcd2cf0..7289ed5 100644
--- a/src/librustdoc/markdown.rs
+++ b/src/librustdoc/markdown.rs
@@ -144,8 +144,14 @@
 
 /// Runs any tests/code examples in the markdown file `input`.
 pub(crate) fn test(options: Options) -> Result<(), String> {
-    let input_str = read_to_string(&options.input)
-        .map_err(|err| format!("{input}: {err}", input = options.input.display()))?;
+    use rustc_session::config::Input;
+    let input_str = match &options.input {
+        Input::File(path) => {
+            read_to_string(&path).map_err(|err| format!("{}: {err}", path.display()))?
+        }
+        Input::Str { name: _, input } => input.clone(),
+    };
+
     let mut opts = GlobalTestOptions::default();
     opts.no_crate_inject = true;
 
@@ -155,12 +161,12 @@
     generate_args_file(&file_path, &options)?;
 
     let mut collector = Collector::new(
-        options.input.display().to_string(),
+        options.input.filestem().to_string(),
         options.clone(),
         true,
         opts,
         None,
-        Some(options.input),
+        options.input.opt_path().map(ToOwned::to_owned),
         options.enable_per_target_ignores,
         file_path,
     );
diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs
index 4eeaaa2..3a71dd8 100644
--- a/src/librustdoc/passes/mod.rs
+++ b/src/librustdoc/passes/mod.rs
@@ -8,6 +8,9 @@
 mod stripper;
 pub(crate) use stripper::*;
 
+mod strip_aliased_non_local;
+pub(crate) use self::strip_aliased_non_local::STRIP_ALIASED_NON_LOCAL;
+
 mod strip_hidden;
 pub(crate) use self::strip_hidden::STRIP_HIDDEN;
 
@@ -71,6 +74,7 @@
 pub(crate) const PASSES: &[Pass] = &[
     CHECK_CUSTOM_CODE_CLASSES,
     CHECK_DOC_TEST_VISIBILITY,
+    STRIP_ALIASED_NON_LOCAL,
     STRIP_HIDDEN,
     STRIP_PRIVATE,
     STRIP_PRIV_IMPORTS,
@@ -86,6 +90,7 @@
     ConditionalPass::always(CHECK_CUSTOM_CODE_CLASSES),
     ConditionalPass::always(COLLECT_TRAIT_IMPLS),
     ConditionalPass::always(CHECK_DOC_TEST_VISIBILITY),
+    ConditionalPass::always(STRIP_ALIASED_NON_LOCAL),
     ConditionalPass::new(STRIP_HIDDEN, WhenNotDocumentHidden),
     ConditionalPass::new(STRIP_PRIVATE, WhenNotDocumentPrivate),
     ConditionalPass::new(STRIP_PRIV_IMPORTS, WhenDocumentPrivate),
diff --git a/src/librustdoc/passes/strip_aliased_non_local.rs b/src/librustdoc/passes/strip_aliased_non_local.rs
new file mode 100644
index 0000000..ac7d422
--- /dev/null
+++ b/src/librustdoc/passes/strip_aliased_non_local.rs
@@ -0,0 +1,62 @@
+use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::Visibility;
+
+use crate::clean;
+use crate::clean::Item;
+use crate::core::DocContext;
+use crate::fold::{strip_item, DocFolder};
+use crate::passes::Pass;
+
+pub(crate) const STRIP_ALIASED_NON_LOCAL: Pass = Pass {
+    name: "strip-aliased-non-local",
+    run: strip_aliased_non_local,
+    description: "strips all non-local private aliased items from the output",
+};
+
+fn strip_aliased_non_local(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate {
+    let mut stripper = AliasedNonLocalStripper { tcx: cx.tcx };
+    stripper.fold_crate(krate)
+}
+
+struct AliasedNonLocalStripper<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> DocFolder for AliasedNonLocalStripper<'tcx> {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        Some(match *i.kind {
+            clean::TypeAliasItem(..) => {
+                let mut stripper = NonLocalStripper { tcx: self.tcx };
+                // don't call `fold_item` as that could strip the type-alias it-self
+                // which we don't want to strip out
+                stripper.fold_item_recur(i)
+            }
+            _ => self.fold_item_recur(i),
+        })
+    }
+}
+
+struct NonLocalStripper<'tcx> {
+    tcx: TyCtxt<'tcx>,
+}
+
+impl<'tcx> DocFolder for NonLocalStripper<'tcx> {
+    fn fold_item(&mut self, i: Item) -> Option<Item> {
+        // If not local, we want to respect the original visibility of
+        // the field and not the one given by the user for the currrent crate.
+        //
+        // FIXME(#125009): Not-local should probably consider same Cargo workspace
+        if let Some(def_id) = i.def_id()
+            && !def_id.is_local()
+        {
+            if i.is_doc_hidden()
+                // Default to *not* stripping items with inherited visibility.
+                || i.visibility(self.tcx).map_or(false, |viz| viz != Visibility::Public)
+            {
+                return Some(strip_item(i));
+            }
+        }
+
+        Some(self.fold_item_recur(i))
+    }
+}
diff --git a/src/llvm-project b/src/llvm-project
index 5399a24..b31c30a 160000
--- a/src/llvm-project
+++ b/src/llvm-project
@@ -1 +1 @@
-Subproject commit 5399a24c66cb6164cf32280e7d300488c90d5765
+Subproject commit b31c30a9bb4dbbd13c359d0e2bea7f65d20adf3f
diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs
index e788069..1c5a6dc 100644
--- a/src/rustdoc-json-types/lib.rs
+++ b/src/rustdoc-json-types/lib.rs
@@ -188,7 +188,19 @@
     Constraint(Vec<GenericBound>),
 }
 
+/// An opaque identifier for an item.
+///
+/// It can be used to lookup in [Crate::index] or [Crate::paths] to resolve it
+/// to an [Item].
+///
+/// Id's are only valid within a single JSON blob. They cannot be used to
+/// resolve references between the JSON output's for different crates.
+///
+/// Rustdoc makes no guarantees about the inner value of Id's. Applications
+/// should treat them as opaque keys to lookup items, and avoid attempting
+/// to parse them, or otherwise depend on any implementation details.
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+// FIXME(aDotInTheVoid): Consider making this non-public in rustdoc-types.
 pub struct Id(pub String);
 
 #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
diff --git a/src/stage0 b/src/stage0
new file mode 100644
index 0000000..5ec8f5b
--- /dev/null
+++ b/src/stage0
@@ -0,0 +1,447 @@
+dist_server=https://static.rust-lang.org
+artifacts_server=https://ci-artifacts.rust-lang.org/rustc-builds
+artifacts_with_llvm_assertions_server=https://ci-artifacts.rust-lang.org/rustc-builds-alt
+git_merge_commit_email=bors@rust-lang.org
+git_repository=rust-lang/rust
+nightly_branch=master
+
+# The configuration above this comment is editable, and can be changed
+# by forks of the repository if they have alternate values.
+#
+# The section below is generated by `./x.py run src/tools/bump-stage0`,
+# run that command again to update the bootstrap compiler.
+#
+# All changes below this comment will be overridden the next time the
+# tool is executed.
+            
+compiler_date=2024-04-29
+compiler_version=beta
+rustfmt_date=2024-04-29
+rustfmt_version=nightly
+
+dist/2024-04-29/cargo-beta-aarch64-apple-darwin.tar.gz=5a8c5e48a88e7c7b41eb720d60fbd2e879b97639c7ff83710526e8e6caaf8afb
+dist/2024-04-29/cargo-beta-aarch64-apple-darwin.tar.xz=0d237535ae8d435d99104fa5b9dbf41878e2304bb0f2eb574bf17dd685caadc2
+dist/2024-04-29/cargo-beta-aarch64-pc-windows-msvc.tar.gz=c56733bb6198af0a9b0df9a44ef979150e00de33b70853c239cccfcce23c328f
+dist/2024-04-29/cargo-beta-aarch64-pc-windows-msvc.tar.xz=7da5f887151215ddec640684077d98551fe2aed75a3ece2c73b20698754a70bb
+dist/2024-04-29/cargo-beta-aarch64-unknown-linux-gnu.tar.gz=73851e304a539d41bedc0d8a5d98800c8279ae623d3e58e863f8c1f8b458b01c
+dist/2024-04-29/cargo-beta-aarch64-unknown-linux-gnu.tar.xz=db9c28841344b0154756e19a21795ef6e0c4e27c7844be9996824f1039edaa81
+dist/2024-04-29/cargo-beta-aarch64-unknown-linux-musl.tar.gz=a706c8c7e37b9e80d7faa000c5d179a772746eef071387fb2879fdeab1f1f891
+dist/2024-04-29/cargo-beta-aarch64-unknown-linux-musl.tar.xz=2060634afe1b4a19bae874c6ce3cf4256e613af26e06104b45da5bd71cfb133c
+dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabi.tar.gz=7af61e74faea669fdd41793e4b88eb6a37bfacf845af364ee02bb7cf08c612c7
+dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabi.tar.xz=4759fb3e3d89ead605c4eeba23be5cb9b3ac98086a9de20f8dbfdfa9282ee486
+dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz=4cab18df2d94702e8b551357373bcae60d1023e644148f0f82e8971023362121
+dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz=7de4f0d72b4e5770376ede82b02d6bcfd450788a40375fad34d75524c941d72c
+dist/2024-04-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz=6401391a426cf33d6c58f07e7b2828b178720cb4f2b8577ae932b5f5b7d6744e
+dist/2024-04-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz=c3f6729bc769325046f0f62c51b5bed30068c37dc2a36a6283e50565d8cb7d5c
+dist/2024-04-29/cargo-beta-i686-pc-windows-gnu.tar.gz=d116c97c1242220c7972b63010aee1ed36bf5353e84a06d3561cd5fe9d7dae84
+dist/2024-04-29/cargo-beta-i686-pc-windows-gnu.tar.xz=65eba577f7775b3eef36e7f000b5007264392b20a7759f8ed567f3a45b2877db
+dist/2024-04-29/cargo-beta-i686-pc-windows-msvc.tar.gz=d418a3371b3631328bde2b1e0c3159700f12424e83b1d8ece1349fea90f9e403
+dist/2024-04-29/cargo-beta-i686-pc-windows-msvc.tar.xz=23ae73c776fdb0795944656d743444e3b4c440f45084028206c1aec52333b1ba
+dist/2024-04-29/cargo-beta-i686-unknown-linux-gnu.tar.gz=b6bbdeb7c8bfac2e8a083adb4782caf5321799f47acb4eaf81da32bd11730e9c
+dist/2024-04-29/cargo-beta-i686-unknown-linux-gnu.tar.xz=6b409691da6ddb8c04409667b2c3d9d6429c6b5bf53ad18177248406a5f06cb9
+dist/2024-04-29/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz=24cd888d14a788e8fb5b886735f3c07a028a8681df48a777b2bb971c62a175ae
+dist/2024-04-29/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz=e8eece6412936fe4dc863a5e19e6766fbb20e81da0069ad7831465e638db23da
+dist/2024-04-29/cargo-beta-powerpc-unknown-linux-gnu.tar.gz=8f007a2aa02e35c5ddb2152cc7589092a0e3083211c6aa23e676e3a3ad5a4b8d
+dist/2024-04-29/cargo-beta-powerpc-unknown-linux-gnu.tar.xz=3e423e693dd0813f5d87d9eded94894076258ece56684f3598321cd013aeef3c
+dist/2024-04-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz=2eec5e45e389a52b526a5cf683d56a9df92004f6095936b16cd8d7d63722cc6c
+dist/2024-04-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz=64c5135cbff9d4fa9575074c55e79d85f72cb1783498a72e1f77865b9b2d1ba3
+dist/2024-04-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz=d64552a80ca386728e42f00d7f1c700b5e30e5a6939f32ffa15a7ce715d4c8e9
+dist/2024-04-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz=fe91adce8ba35bf06251448b5214ed112556dc8814de92e66bc5dc51193c442f
+dist/2024-04-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz=77aafa8b63a4bf4475e82cd777646be5254e1f62d44b2a8fbd40066fdd7020d3
+dist/2024-04-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz=c38f0b4adcc8e48f70b475636bbd5851406bba296d66df12e1ba54888a4bf21a
+dist/2024-04-29/cargo-beta-s390x-unknown-linux-gnu.tar.gz=c05df24d7e8dff26c01055ad40f9e81e6fcb3ae634ecc1f7cc43c3108677fa0e
+dist/2024-04-29/cargo-beta-s390x-unknown-linux-gnu.tar.xz=47e8f4ec4d996600e60ddc49daeeb43d4c21e0583a86c12395c16eddc7db76ee
+dist/2024-04-29/cargo-beta-x86_64-apple-darwin.tar.gz=f024bd225b77160dc2fabde78002c8deac5cbb9a35345340964c3b988b0d1791
+dist/2024-04-29/cargo-beta-x86_64-apple-darwin.tar.xz=96c9e44bd9f0c85c793e3dd6043cc4f89fbeeab5ddf0fdb5daefca8f690bce05
+dist/2024-04-29/cargo-beta-x86_64-pc-windows-gnu.tar.gz=517889f222b62150fe16bcfd3a0eb5f353956b0084d85713480197bff4558145
+dist/2024-04-29/cargo-beta-x86_64-pc-windows-gnu.tar.xz=a6653ea4aec51569c1300c044d8bf2517a1f5111f710d12cd352190425b8f317
+dist/2024-04-29/cargo-beta-x86_64-pc-windows-msvc.tar.gz=4cb5b5054dffe6721efbbf29192a67e59cda69ea4ab4791aaec6f314eefa5a5e
+dist/2024-04-29/cargo-beta-x86_64-pc-windows-msvc.tar.xz=08bc45be22e9e4f615d1c9e70500046c8db89045f5d40dcde853c610591712a7
+dist/2024-04-29/cargo-beta-x86_64-unknown-freebsd.tar.gz=9661357ee8ea8973016fdbaa2de3cb98713136dcd25f07aa9f9d101180276815
+dist/2024-04-29/cargo-beta-x86_64-unknown-freebsd.tar.xz=7fab806227d1a3be817602abb121ac7e039ba0bbf81e0a1d47bdcccca74203c6
+dist/2024-04-29/cargo-beta-x86_64-unknown-illumos.tar.gz=4c79bb48cfe64bd38af7fe3660cd8bdc99ec90738a0d8fdf80843ecda910dab0
+dist/2024-04-29/cargo-beta-x86_64-unknown-illumos.tar.xz=0fb9edfdafde1820ccb25c22369cafb0e75e68795effeb615cb284a5837c75ba
+dist/2024-04-29/cargo-beta-x86_64-unknown-linux-gnu.tar.gz=c1902a072e61ab5ae9737a1092732e3972deee426424bc85fcf8702adffdd41d
+dist/2024-04-29/cargo-beta-x86_64-unknown-linux-gnu.tar.xz=d39ea1195dcc95e428bd540abd2db5b5d4c997a7661a41a4c0ca41cbdd18d27e
+dist/2024-04-29/cargo-beta-x86_64-unknown-linux-musl.tar.gz=0edfdb6f6bb2a4a1a96a5e95cec897c444c936e6624bb4a530ffed4847b97445
+dist/2024-04-29/cargo-beta-x86_64-unknown-linux-musl.tar.xz=70c264b7845febdee45d0c6e44b65d47ba7f367ef33ec906a9fd7f992ba7cc13
+dist/2024-04-29/cargo-beta-x86_64-unknown-netbsd.tar.gz=f1bd6417a54f3b53d572ce4af799242db7c11265c71201cc09c78d71be38c13a
+dist/2024-04-29/cargo-beta-x86_64-unknown-netbsd.tar.xz=53569810469c483785333759f86434706ee5368d5e18270ee13a17817ad57d40
+dist/2024-04-29/clippy-beta-aarch64-apple-darwin.tar.gz=7b693bde61a090854527a145455ff774314c65ec0cd47d25a19c76c6a166d96c
+dist/2024-04-29/clippy-beta-aarch64-apple-darwin.tar.xz=2494e9fdd8d342b6bc3e55eecfd555c43e3cca8421f3236df2d5a366288fec62
+dist/2024-04-29/clippy-beta-aarch64-pc-windows-msvc.tar.gz=90307f09c6fcb0c1fbe3ad1522a5381a17e2f69637c6d00f4a2cb5f3149bf736
+dist/2024-04-29/clippy-beta-aarch64-pc-windows-msvc.tar.xz=f7e0dec4a4862bd85d894252366152b3b6a7627e7e5a25ce323fa2db3bd87c2b
+dist/2024-04-29/clippy-beta-aarch64-unknown-linux-gnu.tar.gz=7c719e38f2a1030ae61985205df52f9a0c37b659463a5e2dea8e60e632de2d73
+dist/2024-04-29/clippy-beta-aarch64-unknown-linux-gnu.tar.xz=181ff4ae6adced6522a4c29869be3cc5dac8b961c7c88f2957cd31f831490807
+dist/2024-04-29/clippy-beta-aarch64-unknown-linux-musl.tar.gz=4e0e63e6f200386995e369a2673867d1bc3005d51d6a57c00ca80056dd85316b
+dist/2024-04-29/clippy-beta-aarch64-unknown-linux-musl.tar.xz=3d5b22a13aed6821482e60d9cc8571e2da9d95d82104284b77c56985a35a9c4e
+dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabi.tar.gz=9f788db76a5d55b3ecdd04a70b0e2be466959f76ae9fd3497ca2c503504e0c03
+dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabi.tar.xz=f4d8fc103807fba61d71d88b8e25a7016bfbd1a2905330f9a9fb3d7ba082713a
+dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz=d61bec3d017dd0be43e48350190ad18c0a0269e43d964600b62e1f7fd4f84399
+dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz=c00cbdc41a4da0c313a1a282b0158b059dd34f640b582cb7ca18e3d290ca8fa5
+dist/2024-04-29/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz=52143a530ca5274fbb760beecddff16f860ea787443d3dc708dda7c8f32ca9bd
+dist/2024-04-29/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz=c6d2dfeac6f40811bc9b4cec3c23f9c3bb46f761e006257b9313aa7c1a647b5a
+dist/2024-04-29/clippy-beta-i686-pc-windows-gnu.tar.gz=325d39e426b1907fa17d93c0752d3d73bd95750f4f967c2a84aab2c5dac8a588
+dist/2024-04-29/clippy-beta-i686-pc-windows-gnu.tar.xz=536f591d4da455302029384ed196932d71119ef0160ac5415617d6b777c51123
+dist/2024-04-29/clippy-beta-i686-pc-windows-msvc.tar.gz=c3684c9bf471669d444853bf484880d17e150ecb0e7505de90883382023e343b
+dist/2024-04-29/clippy-beta-i686-pc-windows-msvc.tar.xz=0b00e6132f73d5dc762e359b0005fceab0cf7b01337d8f4aa9eacfb4552f9245
+dist/2024-04-29/clippy-beta-i686-unknown-linux-gnu.tar.gz=c91c1eadfc4cbae360a0eecf11c32d2509b68aca86c7b1de3b102944f43e1511
+dist/2024-04-29/clippy-beta-i686-unknown-linux-gnu.tar.xz=6f7a5a287dd6226c203bb674ff02ec773e5d0813091b2af744b88ecd6997a304
+dist/2024-04-29/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz=58383f094995823ea6db6a87b9ad4b33bdae2264d29bab88ab71ec60ccab3b93
+dist/2024-04-29/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz=dbf4680a6fd4dca54acca5503a7fd94502b8e85819bc02346ae9cecd275e4514
+dist/2024-04-29/clippy-beta-powerpc-unknown-linux-gnu.tar.gz=e28eb32cda42654c0f0247aa8e15f01f73770b36f7626c8d6f1b7659accc56e6
+dist/2024-04-29/clippy-beta-powerpc-unknown-linux-gnu.tar.xz=fcc48a83b748e1e46f9daef40563f8e5abbb0e3f014a168b04f3c700c2ace2b8
+dist/2024-04-29/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz=b626faf3275fcd196cd627e8a36c67721bae16a56f61cd080c79d137b3ec7737
+dist/2024-04-29/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz=2c599d2dc719d69f67625f3c6573fcc4f1ea3266801557dd3892bdb7c761b4cf
+dist/2024-04-29/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz=0bc1f546fe0cef2b9516231ab608de68d55f72022fbc9ced5101b600e005f8c4
+dist/2024-04-29/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz=993294f2ae5202785ab242c1c6567df9c8ab1ef44ad35748c526b7fe854fb94e
+dist/2024-04-29/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz=210a4f0d208e0c8e13a57fb3b3e6c98ab5f620e4988d10a127ff1424ac1d5ca9
+dist/2024-04-29/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz=f10f7df41a13ee2ecdc25d60e697cba2342129a912ef20d8bfca5f611a9ec97f
+dist/2024-04-29/clippy-beta-s390x-unknown-linux-gnu.tar.gz=3e24d2af65f0c9667c9997ce091711b2be48e673de3707cddfd8cda455dfecc7
+dist/2024-04-29/clippy-beta-s390x-unknown-linux-gnu.tar.xz=0e7b8fbd0207489e38c78c2ae1aa0df4fcbdd84741aa50a86379e4d7ede286b1
+dist/2024-04-29/clippy-beta-x86_64-apple-darwin.tar.gz=9c0c47fd97ce72abcd6126315834c62aa7297fe09d447ee4cefa1eb46a116326
+dist/2024-04-29/clippy-beta-x86_64-apple-darwin.tar.xz=49dd65c5340fd804399edfa2402cf255fd9bfce1f4aa7fbb3c193c11bc03f8af
+dist/2024-04-29/clippy-beta-x86_64-pc-windows-gnu.tar.gz=6c1c3bdf097a1846ae08b098c555c0c5e9e9b646c744d6bb5a855789196b8bf6
+dist/2024-04-29/clippy-beta-x86_64-pc-windows-gnu.tar.xz=0a7319d1062f73af1c8f0efe6ad970d10d02259162c5bc84bb1f3a10f3911bcb
+dist/2024-04-29/clippy-beta-x86_64-pc-windows-msvc.tar.gz=52fef3f8a64fa58934a633bd4944e8ba9e15f2c2766d0f302dea1a6523864dab
+dist/2024-04-29/clippy-beta-x86_64-pc-windows-msvc.tar.xz=8fdbe7590e62ab68a2e463b14da2595e8c4592744f578a813f64d430ed7db4b6
+dist/2024-04-29/clippy-beta-x86_64-unknown-freebsd.tar.gz=509bf535622bd26385184ee0c17e4e27a5061a8aeebf5759f24bd578692b2f5d
+dist/2024-04-29/clippy-beta-x86_64-unknown-freebsd.tar.xz=2fcd10ada329ba7633616bebc584dca13f11c465e7cf513e76efeb0c3174486f
+dist/2024-04-29/clippy-beta-x86_64-unknown-illumos.tar.gz=ea8cea0d4a2379bcd0693f6174b25bc1f90a016dbe8280159cbb61d859806fb0
+dist/2024-04-29/clippy-beta-x86_64-unknown-illumos.tar.xz=5a243df8d1345db6bd18e4386ba628e6d302bce1cc572fb447cca4264fda3ee9
+dist/2024-04-29/clippy-beta-x86_64-unknown-linux-gnu.tar.gz=2ee560d3c1e306e103eb06d8e8033cd1489b3f6ff9df3bd8a95e25e977befa27
+dist/2024-04-29/clippy-beta-x86_64-unknown-linux-gnu.tar.xz=aaf6e54184a65ad6592bf03955a84ad12b561afd86064b1ac5fa03cf637052f8
+dist/2024-04-29/clippy-beta-x86_64-unknown-linux-musl.tar.gz=1b3877424a0a0eb507675a50e9d2c793f00ab85f6f12b1e27f871331070325b8
+dist/2024-04-29/clippy-beta-x86_64-unknown-linux-musl.tar.xz=6df5eaae5afb64557ba5c3a53ee3e56dab85455838a6044c7671c1180acfeaf9
+dist/2024-04-29/clippy-beta-x86_64-unknown-netbsd.tar.gz=1ac05ed7b607fff8b77ff203a663e9f4f2487779bc25e2dcd454cdf5b7583328
+dist/2024-04-29/clippy-beta-x86_64-unknown-netbsd.tar.xz=da502375b3cee8b254ab5999809f522692c2d1d90ea0544ad03c0ca514c65ef4
+dist/2024-04-29/rust-std-beta-aarch64-apple-darwin.tar.gz=2fdd35ca3b3e3d6f548f11c93337f5bf2e3c088bc78a79881e6f8e230b38b9a5
+dist/2024-04-29/rust-std-beta-aarch64-apple-darwin.tar.xz=bc16b3a1ab6ed69f0121a117c50cbcd201500dae4d72ad0dab148913d04cc529
+dist/2024-04-29/rust-std-beta-aarch64-apple-ios-sim.tar.gz=9375c786703c17baae1c2066f8d972ac316bc840e478ecd1b94288a1d428324e
+dist/2024-04-29/rust-std-beta-aarch64-apple-ios-sim.tar.xz=50d6818a8dd3ab7a3ddbbd7a062b538d9ff3ceb6eada031d1c22ab1dc7ba512c
+dist/2024-04-29/rust-std-beta-aarch64-apple-ios.tar.gz=56c3a01e8fd5c2ed75df811993b0b724709fb5473cc308ac09e7f5644468f751
+dist/2024-04-29/rust-std-beta-aarch64-apple-ios.tar.xz=3527d1f2c99c806479fb4b3801335dc921b514f171b82cd252cbbfc9ed30b163
+dist/2024-04-29/rust-std-beta-aarch64-linux-android.tar.gz=bf8cae7c66489f1aa27f1dea1b37f0d0ae514a6e21b93ff2dc6400dc88feca03
+dist/2024-04-29/rust-std-beta-aarch64-linux-android.tar.xz=46799f0bc1b3c13877f6cb732774cb3b33e0d8a081bfb56d0f877e79482aa1de
+dist/2024-04-29/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz=9f90fadab5104e1d415edf3b4edfaf7222f9f0d55f849851efdec74ffee16f8d
+dist/2024-04-29/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz=87ed6774202b18691bd6884df6944c7e9fe9c944b57a2837e7a7647518bf94e8
+dist/2024-04-29/rust-std-beta-aarch64-pc-windows-msvc.tar.gz=4a0692ad28f7f130b472ffa4aa766b745ba01fb75aa921f2da6622c9c68750df
+dist/2024-04-29/rust-std-beta-aarch64-pc-windows-msvc.tar.xz=a3d45962489a1e18a87e567cbbc8d3665f38809d0ad2ef15bcf0ff9fb9f470a4
+dist/2024-04-29/rust-std-beta-aarch64-unknown-fuchsia.tar.gz=c724f4eb135f73b9c79618f27a1ab35dc7b9d26ca62ed796accce68f9e747a66
+dist/2024-04-29/rust-std-beta-aarch64-unknown-fuchsia.tar.xz=8eab25782d16bcee75f86ecbb826346beb4a7525b220b45b3ba05a567c6d4391
+dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz=33ab1f8410edf590570d7468dbe2ebb5a0907125bbc8d360a928dcb355f0d0e6
+dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz=d3d870209a55ac96391affaa347c04f48cf98c089ac5056f340b8bb38bcc8e60
+dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-musl.tar.gz=4d2bb72b898c30a2fc8d5d3333c2e99a8e30c15891fab641b6a519dc9f0cb611
+dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-musl.tar.xz=fa343e6b6110fcd0c5dae4287ff1a799de5d7e4a805dbf4e9a034bbaed2bf269
+dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz=f1ec4139783169fd83e1b0184518ed25d26cee7b21f196deecc74e83a1d78725
+dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz=d100be2f6f0346c4b1f5b41aec0c13a47426bf4d49127f2341c8332903e4e782
+dist/2024-04-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz=bab6051e1071a58cd126580f6644decf16edb4473fe4be6a34791610d820a294
+dist/2024-04-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz=d9b68f06ff23629063e92dfc42aa3115a858238d368e4b52b35c1ea4491b1402
+dist/2024-04-29/rust-std-beta-aarch64-unknown-none.tar.gz=96804c2d9accd3242bdc22dad688b2ccee071952477b9c592f099377aee6c591
+dist/2024-04-29/rust-std-beta-aarch64-unknown-none.tar.xz=3fed6812d84bdaf787e85c37e23ba729b81a6d25a2b33fed75320e66e6641c89
+dist/2024-04-29/rust-std-beta-aarch64-unknown-uefi.tar.gz=8da5f301bff35fc067ec7cfb878ebfa5607af7dbc276a6b34a77404432c700d2
+dist/2024-04-29/rust-std-beta-aarch64-unknown-uefi.tar.xz=80d643189dc9af98b6410a01261ce6ad34b1325f3aebf3ff61fb43f1261b41ff
+dist/2024-04-29/rust-std-beta-arm-linux-androideabi.tar.gz=2e86b54b0d1f7fefead11d6383bdc80fe0a7b3ccf58381d2a731e6f1c62926de
+dist/2024-04-29/rust-std-beta-arm-linux-androideabi.tar.xz=9831a0270457cad2798b5ae4fe956c257c7e10ce5ad211793dc467577cdec29e
+dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz=f96bc303c0c2be9cf589f00aa63b2cf3fb8585ca9dd8860fe525821bfa1fe19a
+dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz=e57a053b1c2bb6fad93dfaffedce7f48fa292196fc8ba6fd2f0c74dc810a13a9
+dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz=49b2cb2ba5296871b5fac5ad9a74a2891e8b78321078a455ba4a65e003bebd40
+dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz=0f9c15d834a9d282a4018934759f7b48ef3d275e09679a68c5fd1b3f047d02e4
+dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabi.tar.gz=e59f92827241e670c1aa92b35235ad12340869d59327fb83084b5f4149acbe06
+dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabi.tar.xz=ad1cf96bb1fcceaa016e29e8ad34b4cfd711d2e0bd7cabb9cd7cc28abf64d894
+dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz=14a6d318af85bb9fa5c229e45a88a32a71f44ed02cd90a24bb67921eb64dee41
+dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz=ed6b48502ab9169818bceb300b4e6b4fd63366ad5808b047bf9988dae04c2729
+dist/2024-04-29/rust-std-beta-armebv7r-none-eabi.tar.gz=345e8a023be55e3b88a0c2677ea28c7bb4fcc5f3ab707638de76065c7592c2d5
+dist/2024-04-29/rust-std-beta-armebv7r-none-eabi.tar.xz=6d9b11d08f2d62611327a893b45ba07c36df11f077250496ab0881eb7ac84c65
+dist/2024-04-29/rust-std-beta-armebv7r-none-eabihf.tar.gz=a2ae1bf003a8a12b2ecb6bde9868a978820f184af523f0e4c3fc935edd509423
+dist/2024-04-29/rust-std-beta-armebv7r-none-eabihf.tar.xz=3d1dcf8308f9d4590b429f6abbf8f42f04496ab490ccf4ed8c9e381e6d886cae
+dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz=a54106d27e4ce97463e7867ceff9dd22ba456f840ec23229e6909b37d48ad554
+dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz=e6abfaa0905a00efeaee85b9f93793bab93e2cf4e172c9d829c5ba85006c688a
+dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz=cbed18e5dc61fcecb2920affc3890c3b8ae46b7fe5a80b3288689e18d490f3f4
+dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz=2b58bb0dd5cd2c5f7f93f4c6e9135090b931e0ffa27ff9efe2b8ff9fbbb7e48c
+dist/2024-04-29/rust-std-beta-armv7-linux-androideabi.tar.gz=6a371c2ececd349dfa76a02563069912fc91577ac4446d36c22f96723d7f5e9f
+dist/2024-04-29/rust-std-beta-armv7-linux-androideabi.tar.xz=9325daf41ddab02fa845971c10a5e0538a18c7bea14e66fa0f5f6fb16654c7ae
+dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz=7f5ba76cfb7c85333c8dab76fb4ad3f12ddc254b95f9ee07fadb8e1270a4f767
+dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz=f853b7f929b7a309ed6c08ff8c57d583ce0ccb19270674fb30e63a873834dc87
+dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz=0680005d0a12498b687afc583d4f36bd67d0877cd9d3323bfd2df50d15c27afe
+dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz=a494b78fcad01c83df9522d460ac2d35d2d00736a921381f2c611dc516edaa16
+dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz=cfa555db31b5470e878b0f53d86617e7342e8bf018fe62cb0271dfe13db95f51
+dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz=0a8ccd6d88cbe79a855111fbda45aa1a728de655b6927f3d429d901d2afc6503
+dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz=eac53424001c884a540c42f0b68447349ec5d0601a030c060aaed76d54895728
+dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz=42d78fca62361ff28db5bc43bb01cef7af5c6f4ab2110fe6170c3dce4707aab8
+dist/2024-04-29/rust-std-beta-armv7-unknown-linux-ohos.tar.gz=c88de9f2e667da73177fb9c9309d7f1f467e31c18e3ae50d722c71ec8dd876a4
+dist/2024-04-29/rust-std-beta-armv7-unknown-linux-ohos.tar.xz=24b3c04a42d511cdc8c6107b597be38981114f0574eced493d0e90fc748094bc
+dist/2024-04-29/rust-std-beta-armv7a-none-eabi.tar.gz=cd4ad182a098c61550265879ccc04733c39110827f7ef62eecfb8c120ae4ece8
+dist/2024-04-29/rust-std-beta-armv7a-none-eabi.tar.xz=8499a014dfdf448f474a58f148784c2eef245dc909587d876d2fb9ddc6a4ec3f
+dist/2024-04-29/rust-std-beta-armv7r-none-eabi.tar.gz=e8e1870e5b12b3d8643d712efb91eb86b2081284cada4a140c1526692ab183c4
+dist/2024-04-29/rust-std-beta-armv7r-none-eabi.tar.xz=d6029121eacc44bd4dcd9ef6dd3cd0d775cb6e9a3d99f3d62d746fcbf8981cab
+dist/2024-04-29/rust-std-beta-armv7r-none-eabihf.tar.gz=1e0fc42c3802e205130c01ca90f92d793c1c5427b34da66fe77b97cf67b4a5c1
+dist/2024-04-29/rust-std-beta-armv7r-none-eabihf.tar.xz=4c8cfdb11bb686111fa4842d13430c86d9d14ada30e9df334b3777fe899233e0
+dist/2024-04-29/rust-std-beta-i586-pc-windows-msvc.tar.gz=ff895c1b39b84587f10903f4be13d275b545e690da6761190d12c01acc25c6d8
+dist/2024-04-29/rust-std-beta-i586-pc-windows-msvc.tar.xz=fdcbcff7b740235bb16e44174fff9080a7c0a31be358c8abc41805c02c20c3b2
+dist/2024-04-29/rust-std-beta-i586-unknown-linux-gnu.tar.gz=6b227f3b9001e148b66b7001f753a6f88fef9677e39d8fcf4d9c35fe8d345568
+dist/2024-04-29/rust-std-beta-i586-unknown-linux-gnu.tar.xz=1e29297beb8de3778ba958731294823d9a93aac1e0d8833abc5aa99e2935965b
+dist/2024-04-29/rust-std-beta-i586-unknown-linux-musl.tar.gz=26481ad5f22a319830d42f69b1c0195bd65900ebe112e659432334b3468f3d0e
+dist/2024-04-29/rust-std-beta-i586-unknown-linux-musl.tar.xz=c8a837e0d9da8ad976fc1539541c085365aac9dd28b34e4a289d38a823d1b065
+dist/2024-04-29/rust-std-beta-i686-linux-android.tar.gz=f05e28a52f17e22f36ffc70018012a1fe6a07f4b461e774b36464f32bc8f8dea
+dist/2024-04-29/rust-std-beta-i686-linux-android.tar.xz=f9501b2691c51e54a6f4cc6fb72e41901eb551d3a7be5f82a94ce2d3e217828b
+dist/2024-04-29/rust-std-beta-i686-pc-windows-gnu.tar.gz=8d9a782d4f7450bca536aab45147c6ef08bc3847b43fdd171c6449e29762eda0
+dist/2024-04-29/rust-std-beta-i686-pc-windows-gnu.tar.xz=4008712e03fb6494eaba3d79051c5e3fdd93d4c52ae8d86cf8f344b5f051cbca
+dist/2024-04-29/rust-std-beta-i686-pc-windows-gnullvm.tar.gz=cfb23242e495834a3d0f7ffa3da4a0b206dcae35872b1455b11faeee5511ba5f
+dist/2024-04-29/rust-std-beta-i686-pc-windows-gnullvm.tar.xz=95415742c0171945ffc2b67c913ebd1330e29634af238f5ccc843a965340374a
+dist/2024-04-29/rust-std-beta-i686-pc-windows-msvc.tar.gz=e9354d69e39ecfac1d2928664d17d73f808256a4076b849171a9667705c0aa08
+dist/2024-04-29/rust-std-beta-i686-pc-windows-msvc.tar.xz=a34bb0a91170d84195f35ba52afa4c9be8a2f2706dbeea02bd6e8908e08ac65e
+dist/2024-04-29/rust-std-beta-i686-unknown-freebsd.tar.gz=d65f286de399ccc9e9acaf7a4dc4f885357c750231d54a144ba9a59181814f11
+dist/2024-04-29/rust-std-beta-i686-unknown-freebsd.tar.xz=4c93a7da70a69b2ebbac01df64af16344e523d16470b29e57237b1d0925f7721
+dist/2024-04-29/rust-std-beta-i686-unknown-linux-gnu.tar.gz=1b978bfd1a9234be7ef197c8c98c5a6b625f6fbb7b0fca58695986768bdca176
+dist/2024-04-29/rust-std-beta-i686-unknown-linux-gnu.tar.xz=98d4eb5b89a593c8c4f86244c9a7c737d9c18c0168aebe5923b8d9145adcf89a
+dist/2024-04-29/rust-std-beta-i686-unknown-linux-musl.tar.gz=dbf9b3c5b54b3eb0727f976f5632c5b0fcb2f90ac7453962d6cef20f7dae4284
+dist/2024-04-29/rust-std-beta-i686-unknown-linux-musl.tar.xz=f209ade093753342dda6e710ee832a538dbdaa08a24d606f9a2a1bc59b83da29
+dist/2024-04-29/rust-std-beta-i686-unknown-uefi.tar.gz=3c3ca7f34569b2c70c6b223754418a535dd7dfa087ab6e28ed2ec78d20065887
+dist/2024-04-29/rust-std-beta-i686-unknown-uefi.tar.xz=72a7cd0f430ab40d80e93f409b8e26a181010ab4bb75d151e829d51ccdcf8c62
+dist/2024-04-29/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz=b7dfa59bb05cf806c87854d6fce5ef0f160697052fdf6e5a0cad121499108608
+dist/2024-04-29/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz=88bc22f68bab3367cdfa91676418ce1ffc0ec002afb32aed7def880bdd4be402
+dist/2024-04-29/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz=d61019048b941064a99d19e46ff3236a88a2e8fcfb963cedd1d9d1c47963c170
+dist/2024-04-29/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz=7474bda08134c676d74afe5263317af3f271963d8ceaa5efbfa1b657f885c572
+dist/2024-04-29/rust-std-beta-loongarch64-unknown-none.tar.gz=e089c77d433d838ca02d7531d6f4a1770fb4a0568acbd96c8f43034d76f2990b
+dist/2024-04-29/rust-std-beta-loongarch64-unknown-none.tar.xz=364ae6c89c7a930098286e55193d2f5ee3d5ea80b7cca73046e41725f4a8a2f9
+dist/2024-04-29/rust-std-beta-nvptx64-nvidia-cuda.tar.gz=c17bfad87d16f3a8d26646525dc59a352718db9e7572acb583b68a18cfdc338a
+dist/2024-04-29/rust-std-beta-nvptx64-nvidia-cuda.tar.xz=f5c4ecef1c08d19ba6fddbd359a0ce94e46888021cae057fce969276026d086c
+dist/2024-04-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz=3e7e13b0d2e804d228e1e3a9dac0205d294ae29dcc37132f15fb1e218861eb39
+dist/2024-04-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz=ea31b7678e6f64c2f9c28a9af120be04ed6f2a25a496e40afbf6e9aa0dd20b60
+dist/2024-04-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz=f0e1b314c3d5ad1676c68c112581dce62fa06ad557cd5f61034e147b064ed270
+dist/2024-04-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz=8ab7bbea6e2f72df1286facc7d306d01809a4dd9f8901dfdec7e50b594658d49
+dist/2024-04-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz=48f6abda1c7dac185858744aa2cdc3513cdfb6552535282ee83cf9c5365573c7
+dist/2024-04-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz=d920d97f15b56ba6ea81e08b3c29dc7f44f5f30b7513c53446edf95843c332af
+dist/2024-04-29/rust-std-beta-riscv32i-unknown-none-elf.tar.gz=0a198a770f6e6043e923b0ab1a508fd8b190612d0370c33c8dd2c5f63b6f19dd
+dist/2024-04-29/rust-std-beta-riscv32i-unknown-none-elf.tar.xz=424a93313cfe2d85acf956be3d9ac71ea8e34ee61617a550ad6ff5360e1dff52
+dist/2024-04-29/rust-std-beta-riscv32im-unknown-none-elf.tar.gz=2e2b0a8e41f4ea774d665d6248cbc2fdbe3e582206efeb87d250786ebaad0b1a
+dist/2024-04-29/rust-std-beta-riscv32im-unknown-none-elf.tar.xz=2da372c091017b7096e473e5c7016a504d2e041e14173d2520086cb43e0a615a
+dist/2024-04-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz=69d3b21403181b2df14243816388169db2466477ec34bcca5693fb017703686c
+dist/2024-04-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz=281b9c20f8641a3d1b349e762b7f713fb0b91da0d21eec798e639e36a0ea3dab
+dist/2024-04-29/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz=dd9bfd3fd8446d35180fe781139dfb4e04dd658b112eb2a749e8f4aea14f0271
+dist/2024-04-29/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz=b1366375e0c5f53da581741dec91972b0c46d7d466052539207e8feaab0ba3ec
+dist/2024-04-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz=7c6650d8cf8abd51547010e8211af3ef3195099ef43a563460ad4780de20ba17
+dist/2024-04-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz=bab46f3c0078ce346de563bb7a248ca92f15dbdc73bf5a3bc520486118442320
+dist/2024-04-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz=01735b4ad5bc0a53087dd0ccaef2cf174b27e45bf4d2e3c15e64f7522f059c63
+dist/2024-04-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz=0bb272c2c235583ed3e9ec151b3bfc601f8cd07822c2fe47a1258b358be507f0
+dist/2024-04-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz=b2c7f8ee0efe6d0812e4b5dd0979f60f105b84d34d4f600ef75f2eacd954893d
+dist/2024-04-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz=0d5301fc553a6911af6643ab7f57b6438bf649ffcd050d486278c0c5fe38eeba
+dist/2024-04-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz=0d1d35ecb88ee717720ad8e74bd5b602fd6011fe321baddb939f3b161e9cd8c5
+dist/2024-04-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz=a5cf0b98596e68e6f72be2e83c61b8aaa19ead42f248ee2408a3b8f4e97a6657
+dist/2024-04-29/rust-std-beta-s390x-unknown-linux-gnu.tar.gz=629ed749cdae110668ad9ddbc5c61e99e8d400f3dd0981146c3820deadc360f6
+dist/2024-04-29/rust-std-beta-s390x-unknown-linux-gnu.tar.xz=192819438ed27a565cdb67b51d2f5caeb6ae258de86191d6922574327f132acd
+dist/2024-04-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz=84286f6cf6f00f3c92dc881f64a31e1ec5910102d8d3d4faf6fc7e2ddf1544a7
+dist/2024-04-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz=304b5f876b47dcbb7c3483c49295b822e8ba83234bb568ce67896ae4773ae2fa
+dist/2024-04-29/rust-std-beta-sparcv9-sun-solaris.tar.gz=25062159b859e21dda76ca22d4a31d3aba4fcdb0def78bc5b5cf9887c07c1be9
+dist/2024-04-29/rust-std-beta-sparcv9-sun-solaris.tar.xz=5d557ee86457f288462603fe53bcc2e092d84faee543659419fa68c1bd88f554
+dist/2024-04-29/rust-std-beta-thumbv6m-none-eabi.tar.gz=a9663048aad82ef832b2cf82fa9fb94be047f77e283e8aa3e2df6ad957d0782d
+dist/2024-04-29/rust-std-beta-thumbv6m-none-eabi.tar.xz=4c4b703a846b4123d09c1eace6322e82784a004b278f1f3b1ca1279e96207f18
+dist/2024-04-29/rust-std-beta-thumbv7em-none-eabi.tar.gz=32907c33f240abb1cb17ac438da42c5fa3932b270ad08fd6914775c5b59a02f5
+dist/2024-04-29/rust-std-beta-thumbv7em-none-eabi.tar.xz=112583227d2b6abfef6eeb78d980bf2efef392f3b66e433c4959a642d72ffc7b
+dist/2024-04-29/rust-std-beta-thumbv7em-none-eabihf.tar.gz=7ba0084527a18479c4b6f6a0dba8ae23a0ed50e9fc5fbfce23cae1babb5a1e12
+dist/2024-04-29/rust-std-beta-thumbv7em-none-eabihf.tar.xz=49eb4e2efe3a76713ce1fecacaf915717eeed8552912b92895c7fee068a85a36
+dist/2024-04-29/rust-std-beta-thumbv7m-none-eabi.tar.gz=518a532b52f2dad2825158614cd00b12aac6c6e1983a1ad53e2b0e26d1f1b845
+dist/2024-04-29/rust-std-beta-thumbv7m-none-eabi.tar.xz=2895e5796a29fd016462694d880e38eb191cb92c9bdb14414c1d6e63b23d3394
+dist/2024-04-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz=2af590c063344c4c3f65d704fa255232b5f5954872d03c4c55d48662cbe6bb17
+dist/2024-04-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz=a09df5f38183d9fe6116c807619f812410763ddedf06055bfe8040b5794104d3
+dist/2024-04-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz=eac22c4972bde3a57cf2ec4e31b43db3c4b7d961ae31475d8942e898c07640cc
+dist/2024-04-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz=104f2c6490e30cc47833edbd806c2efe6256d1194600b2278339612f94704d45
+dist/2024-04-29/rust-std-beta-thumbv8m.base-none-eabi.tar.gz=b3c9c9d7ce8c1db6f20e8ede542e67aacd6047c52882a5d06c4f96a40a7304d9
+dist/2024-04-29/rust-std-beta-thumbv8m.base-none-eabi.tar.xz=76bfb114bc7674792934a4892d2db41fdc8f5bd30c3aa96c43e8055199157476
+dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabi.tar.gz=1308335fe80dcafaba511ee589959d461145533de5f76118fee29a7e9a15841f
+dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabi.tar.xz=cb8acdb8920983c03b9495cf3506a3014384b4d2f6a53e7907924d38a0baf7f0
+dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz=9dd2e5ce7534ab4fbb93ff652196e877f4e9eea3863920c3d34a05d9a3598c81
+dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz=4b6e962facf7c54846965a8d6880e4a980804459151f2e22ac5af79bc79e26bb
+dist/2024-04-29/rust-std-beta-wasm32-unknown-emscripten.tar.gz=731603392b6e3d36b3a4956928d084e293ef18c8b8593efa756e753a2a309709
+dist/2024-04-29/rust-std-beta-wasm32-unknown-emscripten.tar.xz=8b681b3af47855eb63c4ffe06a2bc6bc4f365354ffbc171ce8cbd8c2a3588a07
+dist/2024-04-29/rust-std-beta-wasm32-unknown-unknown.tar.gz=7b87e59391493c3147c03794061111e25bdae669aea58190a951cdef111e75e0
+dist/2024-04-29/rust-std-beta-wasm32-unknown-unknown.tar.xz=d15eaadb101027906c2fce15b95a3f820bdbc4cf145b705bafc2ac5291289c3b
+dist/2024-04-29/rust-std-beta-wasm32-wasi.tar.gz=07390ec742b79ec11b2c3ec65f60efe5d7c616f50c33058fce346f6e9ad21af3
+dist/2024-04-29/rust-std-beta-wasm32-wasi.tar.xz=79e34d46621c298cadb98c00ce3b25d97474aec300d85255153b47e21b7bb744
+dist/2024-04-29/rust-std-beta-wasm32-wasip1-threads.tar.gz=b916dc9051b0278f820ea0b093db3ecae2e27de641ef67a9b508df75dc92c938
+dist/2024-04-29/rust-std-beta-wasm32-wasip1-threads.tar.xz=2867922a39da3b02ebdb93fb78b010695daf468f87485ad8ab79c7f3eeb18b11
+dist/2024-04-29/rust-std-beta-wasm32-wasip1.tar.gz=792b718c0a72e97ba85a17ba67ee09e55b85de829fe4021f828ce54ff8cb31e0
+dist/2024-04-29/rust-std-beta-wasm32-wasip1.tar.xz=abff86499119bddfeda9059004549941dbcd3d911702d4a9c198b94f60e60f4e
+dist/2024-04-29/rust-std-beta-x86_64-apple-darwin.tar.gz=0bcc7698efafb42a37f20815f5660e39829a42a2776304e7129d0a4ec0c7520b
+dist/2024-04-29/rust-std-beta-x86_64-apple-darwin.tar.xz=c437626e250b0d06c05dc828ab81d0d2c543ffce4b100567910508974ea50045
+dist/2024-04-29/rust-std-beta-x86_64-apple-ios.tar.gz=7c98c9f491bfc837111769a45c10ce2f1ef73c22377158ef9ae80b38034892c0
+dist/2024-04-29/rust-std-beta-x86_64-apple-ios.tar.xz=f4bda724e6e382e02ddf4e4e7a479120420666a5a1ad3c87a85d4d3c763f2cb2
+dist/2024-04-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz=01efbb2e48045318e18bfc7b6c190b461a219e81fc1cca6c855bf0c658aef556
+dist/2024-04-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz=9bff316c6d2fbb3c0889f9ffe4eae496b293fb3afaf8d597155e6badbf0c6a8e
+dist/2024-04-29/rust-std-beta-x86_64-linux-android.tar.gz=5da713547a8af2c86da7db5d8aa4c27188dea1089fded81ffbbeb0f78952a10f
+dist/2024-04-29/rust-std-beta-x86_64-linux-android.tar.xz=9d6a45d6af395360c63ce97bcfc2f9a2967c708afcd979f17fa447239703a92b
+dist/2024-04-29/rust-std-beta-x86_64-pc-solaris.tar.gz=d1a71110bee002c8edfbcc00e0f5eede5afa005b09944bb2cde469c658049e70
+dist/2024-04-29/rust-std-beta-x86_64-pc-solaris.tar.xz=6b8d18c83b9fffdddf9e55c807dc7d5784cc6d7ae90a57c29b87d707f0656964
+dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnu.tar.gz=28921ee14426f54aa09523547516437130654b2d9814120d286f209666c88533
+dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnu.tar.xz=7c3125cce30978ca2619e9aab150cb5b9b2535fbb6274d4ac1b1d4342c7b0220
+dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz=ee5c237f092f8a4ba797c4c7769dfd4da81b5c86d2f4b88704d127642d222a22
+dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz=30c84b04bd2d4d33abf1875cfee5f227ef6484edc67b3cc4c9c96d92c8406d6f
+dist/2024-04-29/rust-std-beta-x86_64-pc-windows-msvc.tar.gz=81274050e72c5a8ffdead83f7be62434f35a65517a1b3c6f7d9d14d0d59da710
+dist/2024-04-29/rust-std-beta-x86_64-pc-windows-msvc.tar.xz=215e20c78a2a4edf9b8368a29a09af5f4cf8d0edd1995de3bbf2eff01127cab7
+dist/2024-04-29/rust-std-beta-x86_64-unknown-freebsd.tar.gz=340131cba121827a9753e19cb3a4b9ba2ebe30569fb20d7f9300b4dbe2a15cf4
+dist/2024-04-29/rust-std-beta-x86_64-unknown-freebsd.tar.xz=69626178bc5309afc8a02c941bd77e70e1aa6917ffb6bf0d67a57d921b5c664a
+dist/2024-04-29/rust-std-beta-x86_64-unknown-fuchsia.tar.gz=22c6c90533dad3a731ad8a6696e6cdc1b15579e25c658fa2b094185e1893934f
+dist/2024-04-29/rust-std-beta-x86_64-unknown-fuchsia.tar.xz=30d7ef6684fa98e28037b69d4220cba40489c23e80fe7793c98b388dc161757d
+dist/2024-04-29/rust-std-beta-x86_64-unknown-illumos.tar.gz=9d7192d32eaa6b6ccb0f615da0f4cd80827ba6484eabeaf401d8217678f1e313
+dist/2024-04-29/rust-std-beta-x86_64-unknown-illumos.tar.xz=7a3fb35e0bb252d5f90773136d1417c26d5601beadb77d6da6f5ad3081977f07
+dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz=e987635519c1edc8a1d147ca4a86283637e4dbd0a49736b01d605e45a3a14e8f
+dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz=c3ab6b97dccc0038c68494b03b6d444d534e447226a2b2e140af54c94fca0b2d
+dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz=72e8113687be8f947c50befb42b0957dd564f01693cf4d68d749a9e074032ada
+dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz=867b24f33b19f40727c71818c8a002718d44d4cd4ceca44314331e19c1adc1a4
+dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-musl.tar.gz=f9b0fd9605bd4e264f5303bd740d9a0195bc147132969965b221f9da0d7875bf
+dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-musl.tar.xz=022dcf4887df41d776ba2666858b9aaab479758134a71f7c6b2172ed7c1a1752
+dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz=b5ff4a0ecd7e0f71a9557b6096bb907e5cbc8982431f0d9b01d8e1a895d8b37e
+dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz=e40d5bfb46aadf6faf849df548154db3f35f356f8b98037a056802a235922b8a
+dist/2024-04-29/rust-std-beta-x86_64-unknown-netbsd.tar.gz=57cfb1fa472dd9c01fc0caf605a55b7248375d616acf84ec12f6430d5e07e2ee
+dist/2024-04-29/rust-std-beta-x86_64-unknown-netbsd.tar.xz=e4121f060b917c811d971e85ce02495e83150ddcceb2204615edff24bd55bfa6
+dist/2024-04-29/rust-std-beta-x86_64-unknown-none.tar.gz=d63559803c8eb47e0d10d9f3a2284477b570a2536bb541762774271451e1f0ce
+dist/2024-04-29/rust-std-beta-x86_64-unknown-none.tar.xz=5388cf8ecaa234d507e505e8c6d433c5de8811b2717aa254e4caac9f4aa6cd97
+dist/2024-04-29/rust-std-beta-x86_64-unknown-redox.tar.gz=0f027163f37618df4330ecd82afece432b0a509ab20333d7b787c0d139ea89c2
+dist/2024-04-29/rust-std-beta-x86_64-unknown-redox.tar.xz=b1c722e894b145c2183183fa58762c64402fac077419dc7874f8b08eee665651
+dist/2024-04-29/rust-std-beta-x86_64-unknown-uefi.tar.gz=24e2ac0d44619ef9b76cb1af6178103d65ab12e2677b366e8aee0604798fe5f1
+dist/2024-04-29/rust-std-beta-x86_64-unknown-uefi.tar.xz=1d8a45f1bfe6650edc5ddfc8683190eff5a74384abcb2f73eb3d1e88d566ccfc
+dist/2024-04-29/rustc-beta-aarch64-apple-darwin.tar.gz=ea113c567692d54983ab6c376761651b6dcf9bedad5b5d822d28c0d0d0733cf2
+dist/2024-04-29/rustc-beta-aarch64-apple-darwin.tar.xz=e36363f1ea531d2fd563f471758e387de37a34e7ef6f4c12175979657333c5b4
+dist/2024-04-29/rustc-beta-aarch64-pc-windows-msvc.tar.gz=52d77d540fc3f83d82f35f358ccd9055fb75453af3e3bee4b11636742559db13
+dist/2024-04-29/rustc-beta-aarch64-pc-windows-msvc.tar.xz=843c56f5431c1feda85ceaeef0daf988e8ae020b3556326fb1f75ea7968bf2df
+dist/2024-04-29/rustc-beta-aarch64-unknown-linux-gnu.tar.gz=ba2fe37dda1a487a2c75151895f4f6e886e9476a992272ce26e9b5fd7adb11f9
+dist/2024-04-29/rustc-beta-aarch64-unknown-linux-gnu.tar.xz=ccb7be3935de1920509d2061d38f92f1fb8d2a5dd6cef392492242a929363fa9
+dist/2024-04-29/rustc-beta-aarch64-unknown-linux-musl.tar.gz=40636e0936bd311803317825c5fb6b446cdb5536ada1db097b567df04a86d7dd
+dist/2024-04-29/rustc-beta-aarch64-unknown-linux-musl.tar.xz=804ef68f24bc0ba5150177d8b8515daa54aa82fcb61472385ef1a1d897c5c3e1
+dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabi.tar.gz=a320c2869d1d2c92b698397d4467c8498cad9481f38d28ac810bd165399ca46b
+dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabi.tar.xz=7ce92211d87068d9c223806929adc34ca611a1321cd58b5bd81aabb0ec3ff085
+dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz=79c16b902884301882d16be36fe75ecb32a8e49abde0038ce21cfbee883c2c3a
+dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz=9384eb9bdbb585b414b6c04c592a79e90a0c0ebfeeb970e5e1b920cb638807cc
+dist/2024-04-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz=ff99de5b819a4fb9adce9386a309b9841bd33632eb7d5079415a6ca6fc86b9dd
+dist/2024-04-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz=55635cde13af11dd8cc007d2e0499bfee493bdfba87b6efd7b1fa4115f5728dc
+dist/2024-04-29/rustc-beta-i686-pc-windows-gnu.tar.gz=de82ac745275f069225b84574ed145afaf9f54abde5246592e49d5d1cf40cac1
+dist/2024-04-29/rustc-beta-i686-pc-windows-gnu.tar.xz=a8a7bf64d33c95a2f94265fba8dd9ac50bbb727f4bc3e79be5bf61212cb5d22b
+dist/2024-04-29/rustc-beta-i686-pc-windows-msvc.tar.gz=88967a99c993d6e0c3c7948308510644286ac826266dbd3d89aaa083100711db
+dist/2024-04-29/rustc-beta-i686-pc-windows-msvc.tar.xz=1804f75786482946258ff0e827274357c49e90a7f2f568add7353249f2ab78b9
+dist/2024-04-29/rustc-beta-i686-unknown-linux-gnu.tar.gz=3cb7e02c61d4a21d8289289b874b25e8b020c1d553e5af950160bffc14f51c18
+dist/2024-04-29/rustc-beta-i686-unknown-linux-gnu.tar.xz=2ad4b1311a0e39c359798375912faa91b4e13cd473bd59efd1e4f721777d254f
+dist/2024-04-29/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz=ab19efb741a127615b9022dedf1d895b53c69740cc3da745f9b9888bade9d98b
+dist/2024-04-29/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz=492cc11d54df410c2547890803930fc65950e6b81ced512e24bef56c3e70f3d2
+dist/2024-04-29/rustc-beta-powerpc-unknown-linux-gnu.tar.gz=c5a631a41f417336f3f65c85adefd1fb0bacc02465485f37d29fc1223c9f6cec
+dist/2024-04-29/rustc-beta-powerpc-unknown-linux-gnu.tar.xz=0701183b615d9eec9daea724d4cd8fa98dede2260cfb6b137d6cbf8ad6b29a4f
+dist/2024-04-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz=cb70e92d5275862b500614d79eaea3d19319b96798f4850cb19dea9a8038a651
+dist/2024-04-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz=908cbe562d82cca1bf176fdc99af867966ea423d244c4a50e14bad19f6878201
+dist/2024-04-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz=8580a3eb6d6df1774f4b6ca06dc1195c42b1e2a463488a5d851e99b0ca6d0249
+dist/2024-04-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz=2627948036e905f2e280663c56c86c172e2b0d057311ade7ca238953b7e0c36a
+dist/2024-04-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz=526e4f129fdb4b2c8f4317c57105a09ff03e71771d6d6bbbc9380917b5440d71
+dist/2024-04-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz=fd9dcf60838376478d7cc505ec7fc39f86f9d042646a3b836e9c06825927c7eb
+dist/2024-04-29/rustc-beta-s390x-unknown-linux-gnu.tar.gz=664c1255a9435d1ad086329a3c215974b9302d481762240cc9d0328d9f1b8c9a
+dist/2024-04-29/rustc-beta-s390x-unknown-linux-gnu.tar.xz=a585ce7684e4174f03adb09df17221e1729e8179dbc91b9a0f8813c3ecc0822d
+dist/2024-04-29/rustc-beta-x86_64-apple-darwin.tar.gz=59a1d91009b506a5bce3c276993cb8acfd71f73d01f9eaf4195b36114ac822c3
+dist/2024-04-29/rustc-beta-x86_64-apple-darwin.tar.xz=f86f3309cf2784b076f14e7da9e921c294a7701ea92d378c609061deccbc6bff
+dist/2024-04-29/rustc-beta-x86_64-pc-windows-gnu.tar.gz=f5c074461409b33a9791325d4014e6861ad36f99b9e48e54ecceb73986450be1
+dist/2024-04-29/rustc-beta-x86_64-pc-windows-gnu.tar.xz=045431eec6f839b1c40b5a75c5000f80bd6351274a59b29d962833495324ecb6
+dist/2024-04-29/rustc-beta-x86_64-pc-windows-msvc.tar.gz=a3abfb68e60544170f47209bbf048f1374e5bb75901a529e2ac2f315758155f8
+dist/2024-04-29/rustc-beta-x86_64-pc-windows-msvc.tar.xz=398c41a3219781c7cf1a907406506526b672abca6d3ab59c30556390a5f992c9
+dist/2024-04-29/rustc-beta-x86_64-unknown-freebsd.tar.gz=38895e615efd0bf75ca14b0ab0a085527cca64fae17631d1780a8f51acd26d17
+dist/2024-04-29/rustc-beta-x86_64-unknown-freebsd.tar.xz=786f40030dbe5e6897aafe4bda44770920b2010b93fc5ce86574774e531e2eff
+dist/2024-04-29/rustc-beta-x86_64-unknown-illumos.tar.gz=7003cab7650dae7e3d29032422a57782a2c146024c437a6466ae1dd2b61a6618
+dist/2024-04-29/rustc-beta-x86_64-unknown-illumos.tar.xz=bed3cc10203e8bd4d43b6245928c8a607acc5b6e633635caea45eb4eef4bda56
+dist/2024-04-29/rustc-beta-x86_64-unknown-linux-gnu.tar.gz=84cdea91c9f1e848ea17f554229ca80d18d093fc609641d8f003c4f2d4871866
+dist/2024-04-29/rustc-beta-x86_64-unknown-linux-gnu.tar.xz=a20fce7512f7c8cc6230a0f63f12855b04370d25e621183f71aa444c90c36b4b
+dist/2024-04-29/rustc-beta-x86_64-unknown-linux-musl.tar.gz=87e0c484ade99efab57c655ef96dbabf7a02314540575b65a14372ab5496c36c
+dist/2024-04-29/rustc-beta-x86_64-unknown-linux-musl.tar.xz=469757d8f35c9f4210aefd2ba660ee249e4409d47b908a6c68c1e650ee81ae67
+dist/2024-04-29/rustc-beta-x86_64-unknown-netbsd.tar.gz=4a38000480fe78fd5da7f9b71d36f296a6ae103254d932c4de6b902354e86bbf
+dist/2024-04-29/rustc-beta-x86_64-unknown-netbsd.tar.xz=45945d6af237fe4c91fde7db02ca19e99bac56a911b8db79be9b6ab8bb3934e1
+dist/2024-04-29/rustc-nightly-aarch64-apple-darwin.tar.gz=0b07375a9a6507fd4932a05b5aaf28ed349fe2040103f1cb69c8a2494437258f
+dist/2024-04-29/rustc-nightly-aarch64-apple-darwin.tar.xz=143bd7ed3ca7b913ddd0cea7cda8d1a0e4c29cc2ccbb7d29f0e45c2a87c3ec46
+dist/2024-04-29/rustc-nightly-aarch64-pc-windows-msvc.tar.gz=9404c111b91fd092367b88adbc37dce10a98c443bd8d9e13a860e1fb4e3af96e
+dist/2024-04-29/rustc-nightly-aarch64-pc-windows-msvc.tar.xz=f9f432907c276edcae5ad8ade0264f3c03109be02e791a814edc8ad3d229637a
+dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz=33425c90427424f0b30fa2a6331a3b59c680f1c1bd0d8845d7e6bc1e2f80292d
+dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz=03792890c64c72f30143849894b15f0eb3d6ad735fceede9092abd900ee733e4
+dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-musl.tar.gz=cf6f2bffa0db1b4b9b8e95801bf415dcce413f902e26f4c1831dff1a00752b99
+dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-musl.tar.xz=9192fdb668df8d4cab776623db7d01e35af42fea94098c1d4ba53190825d81a8
+dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz=a174e7e08da2abc6b84499360670188f5cc61b6d055967e04bf602ff3d831f45
+dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz=5a59811027586863852b15fc2b603e7e69b19841f4c10d2527ef1fc5b77d8af2
+dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz=645bb5dd7a96bb9292b9956cb9705e9aed2408e47728f245564f1f7404ede783
+dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz=1fe34911b082c3a5ca4f24656675c095d2cf56f8005be9ca2517d0ef7d0a2b37
+dist/2024-04-29/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz=f2d6403d81bb0afe2e14956828987a0bb044c95f2d9566e1d792dd922dad7914
+dist/2024-04-29/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz=d93fdafcbbfd50c88c3f4feb4c68b053882ccae02c45e1615aeeae5a86f4aa98
+dist/2024-04-29/rustc-nightly-i686-pc-windows-gnu.tar.gz=a9e997b03559b3dfa2a0eba6ed7a142d7651ea7f4ba4e788d9de807b50558e58
+dist/2024-04-29/rustc-nightly-i686-pc-windows-gnu.tar.xz=4412b5fbfab8c5b31e57cf8c4ce9a9d13cfc9c0a8174ea1fc8a7c05281e1cb54
+dist/2024-04-29/rustc-nightly-i686-pc-windows-msvc.tar.gz=1725c41500dbf6bea554f3d4acaba70167f0e89087aaa3eb3c0f8a99047c55c4
+dist/2024-04-29/rustc-nightly-i686-pc-windows-msvc.tar.xz=27db022494afebbe05605f134191e8b2e78bfdeaa638d4215174038ca9dd2fd7
+dist/2024-04-29/rustc-nightly-i686-unknown-linux-gnu.tar.gz=dc1a05d49b773dba06808c1c50653ecac506b3433f0f6dfa307109a7c621cc1a
+dist/2024-04-29/rustc-nightly-i686-unknown-linux-gnu.tar.xz=cc58ce3af8f5481ada4dc129079cd558664717526b2f7f9a02bde6bafb6f45ad
+dist/2024-04-29/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz=34cfe803126ae9218b17adfe833a55c697dfa50729ac83b642529f3682d12d15
+dist/2024-04-29/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz=c752dc8962656c09047151fd24166f3134fbeed85006b5d22496691079c7fb9c
+dist/2024-04-29/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz=386b086b8aad922050c813dd58bb79a52ef806b2d1413e2e9cc46d6e43b81d7c
+dist/2024-04-29/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz=d9eec9ab7c265444ac5f04d4ec9e77d4c0c3c2e34c5804db8abf5f94c8fd2272
+dist/2024-04-29/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz=91df129046443554bfb836d25886aa9807b917acbc9dcf30f6531cde7bf912fa
+dist/2024-04-29/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz=ca9b574b9f2e914b5a6d9e011aba805d1e6f9b687dc1a1868e88f0e4d9e4401c
+dist/2024-04-29/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz=8b44f96a1ccd6d501b0af3960edb2c1a6c93957676a1c2cdb831e614de398f8b
+dist/2024-04-29/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz=f8a10a6767b80bf24f73223b9e46e1b18b6bf6746ad2115eb8968a0e482f0e4e
+dist/2024-04-29/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz=a197208807503a9cfbc6df938d614a192da48884b2e4892f7b1d234579091be1
+dist/2024-04-29/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz=af3a1a33942bd8a3417593dc118abb1db0373f5410f54771713c05bb86724fed
+dist/2024-04-29/rustc-nightly-s390x-unknown-linux-gnu.tar.gz=5a3a3aa73b6a0f21c63b9a40bdbd0bb4dc59bd75add0a06e292ced791fad31be
+dist/2024-04-29/rustc-nightly-s390x-unknown-linux-gnu.tar.xz=6d7903f1c9fc95a23448717326d667dce59e54aaff821443d3cd9137cf3537fb
+dist/2024-04-29/rustc-nightly-x86_64-apple-darwin.tar.gz=64eede54da4bf88b0a42ecf7f7a4bf8002b5550e60a64e1e48244c7f5b04768c
+dist/2024-04-29/rustc-nightly-x86_64-apple-darwin.tar.xz=0a8f95e3bb0bebf9bcc8116b91bab3ba97cb6ff4021713586280aaceed9da030
+dist/2024-04-29/rustc-nightly-x86_64-pc-windows-gnu.tar.gz=58f9e0dd9c1aadde2dfd869528adadd4acc29ab0850236f3cee5f023d4211939
+dist/2024-04-29/rustc-nightly-x86_64-pc-windows-gnu.tar.xz=a211a962093e0d09358d51a6eb48da0966a02383c6b00c8acc077b5663d7d707
+dist/2024-04-29/rustc-nightly-x86_64-pc-windows-msvc.tar.gz=5631926874dc54204c319137a77a89de5e6f408de2a832109e2be71ea79f27d1
+dist/2024-04-29/rustc-nightly-x86_64-pc-windows-msvc.tar.xz=a8cf87bc663b5e3dbcc97b0eb58bb1b9b5b0100aacb47dc0c372fe1612517244
+dist/2024-04-29/rustc-nightly-x86_64-unknown-freebsd.tar.gz=1011f98197a9fe82d6095f4521934a06eea5f7e9719a6e4c9e3bf13d68f799ca
+dist/2024-04-29/rustc-nightly-x86_64-unknown-freebsd.tar.xz=79599b3f91f9372262e97a417f4e104ef5192c0f6f8df204aea9c8b3ee39430e
+dist/2024-04-29/rustc-nightly-x86_64-unknown-illumos.tar.gz=7179a453bdcb17e401c0af8f4ab86cb5a4752a8ec80b0cbdd4cf1854c7f36a35
+dist/2024-04-29/rustc-nightly-x86_64-unknown-illumos.tar.xz=d565fc366fdbc305fbfe59e72b971c58f201d69e03a9ffa667d2ca0735cdb7f3
+dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz=ae6bd8e20560d48519290d78e3d21f84b983403ca1f8f466a85496276d7866da
+dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz=c7c0f8f44b0275456a27952178caa04c32eb9a1507056ddc05926a0730e17359
+dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-musl.tar.gz=3246797ddbc9118de819b13b005b83748338f3c825a7436ebd5aa79ca55539c0
+dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-musl.tar.xz=c7e784e77dbabedad88d24d2ae6dc4abb68bc04b1cd6c9d45f6dc28b6d0e2edc
+dist/2024-04-29/rustc-nightly-x86_64-unknown-netbsd.tar.gz=c9452de4b3f15f0cf0b7d737b217b2cc7b88a96543bd8ce587ee14be1e21a90a
+dist/2024-04-29/rustc-nightly-x86_64-unknown-netbsd.tar.xz=de9b05278a5c69d53ccbb31223526ea2aa2275c0fb3f046d1c1b4d67c0b0c275
+dist/2024-04-29/rustfmt-nightly-aarch64-apple-darwin.tar.gz=3734353a58dbf6c3831cc6b4ea606357140c191c89e8dfca1d7aa2f3fb8ac53d
+dist/2024-04-29/rustfmt-nightly-aarch64-apple-darwin.tar.xz=e5e3a6e609fbfd537aa4acfefd3681d4b6c8029e2801a1ef23e8b09cf5a47bfe
+dist/2024-04-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz=22f54857e01d759301d099b67547cdc485596499088d0d749d38058c28e0f752
+dist/2024-04-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz=db48a9d45dc7c7aad4c9bb0d20789dd35fb6ef7a966948c44fbbae132de4c16b
+dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz=fa5d1fb9f3627e7d59269a1f8008d780c685ea04975473f1808287134e7bc5a7
+dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz=61ab625b47fa9097af90a79a1e75a2f2492a415f4009c9043cf453bd4128f031
+dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz=cc79969341fc60991059d0e3f13a69489c1e0915ea5787a88b8605ed5b7f3cd0
+dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz=bbdb75f922b4b1716b033d91c76c4c0aa53061d6e7fa53a9bf16fe076814bbb2
+dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz=13ca68afc3f3970a37951504664b58035102e1ae06d10a744389603b2f7499f5
+dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz=04b174aa724945b6359a555892506c6a742a7c427464e8206433bb3f9a65fc02
+dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz=430333380a590a9de211c8d735989fedb89321cf9f5f9a0b1ef651ec8b598691
+dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz=924713e648806945cd56e54d4c11dc74b65241c8dbf6cc7b401c5c93d0f7ffdb
+dist/2024-04-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz=bb6e5a8b5cc88099e613aa5f4d926165976d8e4a7fccbecf4ac3b0eb966d7a0f
+dist/2024-04-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz=34d5e970304e1734aacb26c095e926c27a07e1a41fe70db9fa2997bef97ad3ec
+dist/2024-04-29/rustfmt-nightly-i686-pc-windows-gnu.tar.gz=835447a1d9d60659e99903275f327641809fc0148f35149f980d1a17ff87cc9a
+dist/2024-04-29/rustfmt-nightly-i686-pc-windows-gnu.tar.xz=ddd84a7f900aa239f93711f7da71e57aaedeeba2c9c8a8f23608acc7e48613c0
+dist/2024-04-29/rustfmt-nightly-i686-pc-windows-msvc.tar.gz=02f0af2bdae167c6091099a9b54ceb150c22b0f20dc861587a02cac78deb0b39
+dist/2024-04-29/rustfmt-nightly-i686-pc-windows-msvc.tar.xz=822f78f39dcbe3282bf7888a8cdae04efe7b023ded026a7e7f430e4ff15e7942
+dist/2024-04-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz=68a6189652c11a2c142c5339e2f5fb09d5f3e85d860bff063f62d5d3a3d111bf
+dist/2024-04-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz=6740ea882effa2fb87dd72744c08888ce5ec59c9797c00369156b24847bb180e
+dist/2024-04-29/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz=0bb365e2d895ef3c39c4899a01187a23f9b7c5195c30bf845da3917f62f5eafd
+dist/2024-04-29/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz=2e54c9887bc6ed1eb09b9f69c8425da843ea12bf33248fa0ccdc0d14387c1c57
+dist/2024-04-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz=b0c0fe437921d17e2f50cbff87beeac067efa3d5211a241fb6f4c10b8ab500ac
+dist/2024-04-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz=64e7282c0cf4a714b11eed1d28be3a64ba0ccc6d899211a872a5a7809d514c08
+dist/2024-04-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz=100cfde057c81460b8cfde2047fe83ddde360a6df1ff178da5a968b17ecc9df8
+dist/2024-04-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz=38e8712e98fa0bc6962ab2fd2e3b96a2a5dcaa6c16161d8caf71131a1ca5031e
+dist/2024-04-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz=4dab52b50e19348fb39fdad39ab44189c27c10f80b5fbe2cc4723b644611fa87
+dist/2024-04-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz=36d1b2c9150fafc5976c296200ba3fac3e923df3e6f18032068200e2a887146c
+dist/2024-04-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz=7cb4a536320c23d305ce3bd3b7a954d951bf4d358ef3732be75b9b290c4818a5
+dist/2024-04-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz=ede1afc7dc5892ef6f780e987737e145c4b4d00495da8c2e9902182a3a174e20
+dist/2024-04-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz=e2d2d561cbfa0add0e5349682976216d3a7cff4094372c1ed26854bb4e4d93fd
+dist/2024-04-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz=e0380e65e83e4131f6aa7ee4e185689add4372b0c1653312e2ffd56072fdd0fe
+dist/2024-04-29/rustfmt-nightly-x86_64-apple-darwin.tar.gz=73a140c7ed9c80f209ff976c63b0a34d625d651553c38692c91f048f4e0ae470
+dist/2024-04-29/rustfmt-nightly-x86_64-apple-darwin.tar.xz=9946b7120465181e05916b8023bc075b32bd85cf45a3b1d8bfba2f94ac78d927
+dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz=eda273f27714b1e45adcc2388149f48de0e32a9104db0b9d1a02f6d37de43fef
+dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz=f2955a4b696d050c219a96c093162b42a2fab921f9f3cb7570f8462928306c6d
+dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz=ec900cc2d3c6d45ef039653f4418f9b9a4a5fddd5d7e8077c3fb08b36c539a28
+dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz=04e6999a3405acc79f5fdcafeeab52880e5eeeedd3909b5f3c57e7647c86ef99
+dist/2024-04-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz=0730c5ebd576fec5371085f9fac0adde9424e1d7626456ed33bc66351b0ad307
+dist/2024-04-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz=90cbd84b8d48f0235a1954166f5edd53dc3031532ec6dfcb364f9a9624c9ce11
+dist/2024-04-29/rustfmt-nightly-x86_64-unknown-illumos.tar.gz=5f5c62d321db27eb495f6ea312ef8bea0bf17a7a501a44e062986c416951700f
+dist/2024-04-29/rustfmt-nightly-x86_64-unknown-illumos.tar.xz=a3bf64e2f22436e4484fc818f69d2f750fddd05a96463fd4abfcf655edce36b9
+dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz=a847a6f9c7a3ce71c7cd8d81bdfcfcd8e4d128aa28ba0dafea89b0cc37c6c36c
+dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz=21fa794456566c64d08f629a385f89b3cfe9d9b69f317ae85fbe7425419108ff
+dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz=b3f792f10a98993b4b55d1df951727a4422102d51b1145e51824268d48587ad0
+dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz=d791f0ec3c004e7baa0381962bf8ca2f18a3c861152702de5301d0149260e7fa
+dist/2024-04-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz=9807b2887e976d29f0c04484f8459175b4f6b70ef000037cdc4dada48e3cbd74
+dist/2024-04-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz=019920d64778af62879e2146c2c13d9f6e2165a38bbfa1982694bfb48864d308
\ No newline at end of file
diff --git a/src/stage0.json b/src/stage0.json
deleted file mode 100644
index a9a53a7..0000000
--- a/src/stage0.json
+++ /dev/null
@@ -1,456 +0,0 @@
-{
-  "config": {
-    "dist_server": "https://static.rust-lang.org",
-    "artifacts_server": "https://ci-artifacts.rust-lang.org/rustc-builds",
-    "artifacts_with_llvm_assertions_server": "https://ci-artifacts.rust-lang.org/rustc-builds-alt",
-    "git_merge_commit_email": "bors@rust-lang.org",
-    "git_repository": "rust-lang/rust",
-    "nightly_branch": "master"
-  },
-  "__comments": [
-    "The configuration above this comment is editable, and can be changed",
-    "by forks of the repository if they have alternate values.",
-    "",
-    "The section below is generated by `./x.py run src/tools/bump-stage0`,",
-    "run that command again to update the bootstrap compiler.",
-    "",
-    "All changes below this comment will be overridden the next time the",
-    "tool is executed."
-  ],
-  "compiler": {
-    "date": "2024-04-29",
-    "version": "beta"
-  },
-  "rustfmt": {
-    "date": "2024-04-29",
-    "version": "nightly"
-  },
-  "checksums_sha256": {
-    "dist/2024-04-29/cargo-beta-aarch64-apple-darwin.tar.gz": "5a8c5e48a88e7c7b41eb720d60fbd2e879b97639c7ff83710526e8e6caaf8afb",
-    "dist/2024-04-29/cargo-beta-aarch64-apple-darwin.tar.xz": "0d237535ae8d435d99104fa5b9dbf41878e2304bb0f2eb574bf17dd685caadc2",
-    "dist/2024-04-29/cargo-beta-aarch64-pc-windows-msvc.tar.gz": "c56733bb6198af0a9b0df9a44ef979150e00de33b70853c239cccfcce23c328f",
-    "dist/2024-04-29/cargo-beta-aarch64-pc-windows-msvc.tar.xz": "7da5f887151215ddec640684077d98551fe2aed75a3ece2c73b20698754a70bb",
-    "dist/2024-04-29/cargo-beta-aarch64-unknown-linux-gnu.tar.gz": "73851e304a539d41bedc0d8a5d98800c8279ae623d3e58e863f8c1f8b458b01c",
-    "dist/2024-04-29/cargo-beta-aarch64-unknown-linux-gnu.tar.xz": "db9c28841344b0154756e19a21795ef6e0c4e27c7844be9996824f1039edaa81",
-    "dist/2024-04-29/cargo-beta-aarch64-unknown-linux-musl.tar.gz": "a706c8c7e37b9e80d7faa000c5d179a772746eef071387fb2879fdeab1f1f891",
-    "dist/2024-04-29/cargo-beta-aarch64-unknown-linux-musl.tar.xz": "2060634afe1b4a19bae874c6ce3cf4256e613af26e06104b45da5bd71cfb133c",
-    "dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabi.tar.gz": "7af61e74faea669fdd41793e4b88eb6a37bfacf845af364ee02bb7cf08c612c7",
-    "dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabi.tar.xz": "4759fb3e3d89ead605c4eeba23be5cb9b3ac98086a9de20f8dbfdfa9282ee486",
-    "dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.gz": "4cab18df2d94702e8b551357373bcae60d1023e644148f0f82e8971023362121",
-    "dist/2024-04-29/cargo-beta-arm-unknown-linux-gnueabihf.tar.xz": "7de4f0d72b4e5770376ede82b02d6bcfd450788a40375fad34d75524c941d72c",
-    "dist/2024-04-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.gz": "6401391a426cf33d6c58f07e7b2828b178720cb4f2b8577ae932b5f5b7d6744e",
-    "dist/2024-04-29/cargo-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c3f6729bc769325046f0f62c51b5bed30068c37dc2a36a6283e50565d8cb7d5c",
-    "dist/2024-04-29/cargo-beta-i686-pc-windows-gnu.tar.gz": "d116c97c1242220c7972b63010aee1ed36bf5353e84a06d3561cd5fe9d7dae84",
-    "dist/2024-04-29/cargo-beta-i686-pc-windows-gnu.tar.xz": "65eba577f7775b3eef36e7f000b5007264392b20a7759f8ed567f3a45b2877db",
-    "dist/2024-04-29/cargo-beta-i686-pc-windows-msvc.tar.gz": "d418a3371b3631328bde2b1e0c3159700f12424e83b1d8ece1349fea90f9e403",
-    "dist/2024-04-29/cargo-beta-i686-pc-windows-msvc.tar.xz": "23ae73c776fdb0795944656d743444e3b4c440f45084028206c1aec52333b1ba",
-    "dist/2024-04-29/cargo-beta-i686-unknown-linux-gnu.tar.gz": "b6bbdeb7c8bfac2e8a083adb4782caf5321799f47acb4eaf81da32bd11730e9c",
-    "dist/2024-04-29/cargo-beta-i686-unknown-linux-gnu.tar.xz": "6b409691da6ddb8c04409667b2c3d9d6429c6b5bf53ad18177248406a5f06cb9",
-    "dist/2024-04-29/cargo-beta-loongarch64-unknown-linux-gnu.tar.gz": "24cd888d14a788e8fb5b886735f3c07a028a8681df48a777b2bb971c62a175ae",
-    "dist/2024-04-29/cargo-beta-loongarch64-unknown-linux-gnu.tar.xz": "e8eece6412936fe4dc863a5e19e6766fbb20e81da0069ad7831465e638db23da",
-    "dist/2024-04-29/cargo-beta-powerpc-unknown-linux-gnu.tar.gz": "8f007a2aa02e35c5ddb2152cc7589092a0e3083211c6aa23e676e3a3ad5a4b8d",
-    "dist/2024-04-29/cargo-beta-powerpc-unknown-linux-gnu.tar.xz": "3e423e693dd0813f5d87d9eded94894076258ece56684f3598321cd013aeef3c",
-    "dist/2024-04-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.gz": "2eec5e45e389a52b526a5cf683d56a9df92004f6095936b16cd8d7d63722cc6c",
-    "dist/2024-04-29/cargo-beta-powerpc64-unknown-linux-gnu.tar.xz": "64c5135cbff9d4fa9575074c55e79d85f72cb1783498a72e1f77865b9b2d1ba3",
-    "dist/2024-04-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.gz": "d64552a80ca386728e42f00d7f1c700b5e30e5a6939f32ffa15a7ce715d4c8e9",
-    "dist/2024-04-29/cargo-beta-powerpc64le-unknown-linux-gnu.tar.xz": "fe91adce8ba35bf06251448b5214ed112556dc8814de92e66bc5dc51193c442f",
-    "dist/2024-04-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.gz": "77aafa8b63a4bf4475e82cd777646be5254e1f62d44b2a8fbd40066fdd7020d3",
-    "dist/2024-04-29/cargo-beta-riscv64gc-unknown-linux-gnu.tar.xz": "c38f0b4adcc8e48f70b475636bbd5851406bba296d66df12e1ba54888a4bf21a",
-    "dist/2024-04-29/cargo-beta-s390x-unknown-linux-gnu.tar.gz": "c05df24d7e8dff26c01055ad40f9e81e6fcb3ae634ecc1f7cc43c3108677fa0e",
-    "dist/2024-04-29/cargo-beta-s390x-unknown-linux-gnu.tar.xz": "47e8f4ec4d996600e60ddc49daeeb43d4c21e0583a86c12395c16eddc7db76ee",
-    "dist/2024-04-29/cargo-beta-x86_64-apple-darwin.tar.gz": "f024bd225b77160dc2fabde78002c8deac5cbb9a35345340964c3b988b0d1791",
-    "dist/2024-04-29/cargo-beta-x86_64-apple-darwin.tar.xz": "96c9e44bd9f0c85c793e3dd6043cc4f89fbeeab5ddf0fdb5daefca8f690bce05",
-    "dist/2024-04-29/cargo-beta-x86_64-pc-windows-gnu.tar.gz": "517889f222b62150fe16bcfd3a0eb5f353956b0084d85713480197bff4558145",
-    "dist/2024-04-29/cargo-beta-x86_64-pc-windows-gnu.tar.xz": "a6653ea4aec51569c1300c044d8bf2517a1f5111f710d12cd352190425b8f317",
-    "dist/2024-04-29/cargo-beta-x86_64-pc-windows-msvc.tar.gz": "4cb5b5054dffe6721efbbf29192a67e59cda69ea4ab4791aaec6f314eefa5a5e",
-    "dist/2024-04-29/cargo-beta-x86_64-pc-windows-msvc.tar.xz": "08bc45be22e9e4f615d1c9e70500046c8db89045f5d40dcde853c610591712a7",
-    "dist/2024-04-29/cargo-beta-x86_64-unknown-freebsd.tar.gz": "9661357ee8ea8973016fdbaa2de3cb98713136dcd25f07aa9f9d101180276815",
-    "dist/2024-04-29/cargo-beta-x86_64-unknown-freebsd.tar.xz": "7fab806227d1a3be817602abb121ac7e039ba0bbf81e0a1d47bdcccca74203c6",
-    "dist/2024-04-29/cargo-beta-x86_64-unknown-illumos.tar.gz": "4c79bb48cfe64bd38af7fe3660cd8bdc99ec90738a0d8fdf80843ecda910dab0",
-    "dist/2024-04-29/cargo-beta-x86_64-unknown-illumos.tar.xz": "0fb9edfdafde1820ccb25c22369cafb0e75e68795effeb615cb284a5837c75ba",
-    "dist/2024-04-29/cargo-beta-x86_64-unknown-linux-gnu.tar.gz": "c1902a072e61ab5ae9737a1092732e3972deee426424bc85fcf8702adffdd41d",
-    "dist/2024-04-29/cargo-beta-x86_64-unknown-linux-gnu.tar.xz": "d39ea1195dcc95e428bd540abd2db5b5d4c997a7661a41a4c0ca41cbdd18d27e",
-    "dist/2024-04-29/cargo-beta-x86_64-unknown-linux-musl.tar.gz": "0edfdb6f6bb2a4a1a96a5e95cec897c444c936e6624bb4a530ffed4847b97445",
-    "dist/2024-04-29/cargo-beta-x86_64-unknown-linux-musl.tar.xz": "70c264b7845febdee45d0c6e44b65d47ba7f367ef33ec906a9fd7f992ba7cc13",
-    "dist/2024-04-29/cargo-beta-x86_64-unknown-netbsd.tar.gz": "f1bd6417a54f3b53d572ce4af799242db7c11265c71201cc09c78d71be38c13a",
-    "dist/2024-04-29/cargo-beta-x86_64-unknown-netbsd.tar.xz": "53569810469c483785333759f86434706ee5368d5e18270ee13a17817ad57d40",
-    "dist/2024-04-29/clippy-beta-aarch64-apple-darwin.tar.gz": "7b693bde61a090854527a145455ff774314c65ec0cd47d25a19c76c6a166d96c",
-    "dist/2024-04-29/clippy-beta-aarch64-apple-darwin.tar.xz": "2494e9fdd8d342b6bc3e55eecfd555c43e3cca8421f3236df2d5a366288fec62",
-    "dist/2024-04-29/clippy-beta-aarch64-pc-windows-msvc.tar.gz": "90307f09c6fcb0c1fbe3ad1522a5381a17e2f69637c6d00f4a2cb5f3149bf736",
-    "dist/2024-04-29/clippy-beta-aarch64-pc-windows-msvc.tar.xz": "f7e0dec4a4862bd85d894252366152b3b6a7627e7e5a25ce323fa2db3bd87c2b",
-    "dist/2024-04-29/clippy-beta-aarch64-unknown-linux-gnu.tar.gz": "7c719e38f2a1030ae61985205df52f9a0c37b659463a5e2dea8e60e632de2d73",
-    "dist/2024-04-29/clippy-beta-aarch64-unknown-linux-gnu.tar.xz": "181ff4ae6adced6522a4c29869be3cc5dac8b961c7c88f2957cd31f831490807",
-    "dist/2024-04-29/clippy-beta-aarch64-unknown-linux-musl.tar.gz": "4e0e63e6f200386995e369a2673867d1bc3005d51d6a57c00ca80056dd85316b",
-    "dist/2024-04-29/clippy-beta-aarch64-unknown-linux-musl.tar.xz": "3d5b22a13aed6821482e60d9cc8571e2da9d95d82104284b77c56985a35a9c4e",
-    "dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabi.tar.gz": "9f788db76a5d55b3ecdd04a70b0e2be466959f76ae9fd3497ca2c503504e0c03",
-    "dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabi.tar.xz": "f4d8fc103807fba61d71d88b8e25a7016bfbd1a2905330f9a9fb3d7ba082713a",
-    "dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabihf.tar.gz": "d61bec3d017dd0be43e48350190ad18c0a0269e43d964600b62e1f7fd4f84399",
-    "dist/2024-04-29/clippy-beta-arm-unknown-linux-gnueabihf.tar.xz": "c00cbdc41a4da0c313a1a282b0158b059dd34f640b582cb7ca18e3d290ca8fa5",
-    "dist/2024-04-29/clippy-beta-armv7-unknown-linux-gnueabihf.tar.gz": "52143a530ca5274fbb760beecddff16f860ea787443d3dc708dda7c8f32ca9bd",
-    "dist/2024-04-29/clippy-beta-armv7-unknown-linux-gnueabihf.tar.xz": "c6d2dfeac6f40811bc9b4cec3c23f9c3bb46f761e006257b9313aa7c1a647b5a",
-    "dist/2024-04-29/clippy-beta-i686-pc-windows-gnu.tar.gz": "325d39e426b1907fa17d93c0752d3d73bd95750f4f967c2a84aab2c5dac8a588",
-    "dist/2024-04-29/clippy-beta-i686-pc-windows-gnu.tar.xz": "536f591d4da455302029384ed196932d71119ef0160ac5415617d6b777c51123",
-    "dist/2024-04-29/clippy-beta-i686-pc-windows-msvc.tar.gz": "c3684c9bf471669d444853bf484880d17e150ecb0e7505de90883382023e343b",
-    "dist/2024-04-29/clippy-beta-i686-pc-windows-msvc.tar.xz": "0b00e6132f73d5dc762e359b0005fceab0cf7b01337d8f4aa9eacfb4552f9245",
-    "dist/2024-04-29/clippy-beta-i686-unknown-linux-gnu.tar.gz": "c91c1eadfc4cbae360a0eecf11c32d2509b68aca86c7b1de3b102944f43e1511",
-    "dist/2024-04-29/clippy-beta-i686-unknown-linux-gnu.tar.xz": "6f7a5a287dd6226c203bb674ff02ec773e5d0813091b2af744b88ecd6997a304",
-    "dist/2024-04-29/clippy-beta-loongarch64-unknown-linux-gnu.tar.gz": "58383f094995823ea6db6a87b9ad4b33bdae2264d29bab88ab71ec60ccab3b93",
-    "dist/2024-04-29/clippy-beta-loongarch64-unknown-linux-gnu.tar.xz": "dbf4680a6fd4dca54acca5503a7fd94502b8e85819bc02346ae9cecd275e4514",
-    "dist/2024-04-29/clippy-beta-powerpc-unknown-linux-gnu.tar.gz": "e28eb32cda42654c0f0247aa8e15f01f73770b36f7626c8d6f1b7659accc56e6",
-    "dist/2024-04-29/clippy-beta-powerpc-unknown-linux-gnu.tar.xz": "fcc48a83b748e1e46f9daef40563f8e5abbb0e3f014a168b04f3c700c2ace2b8",
-    "dist/2024-04-29/clippy-beta-powerpc64-unknown-linux-gnu.tar.gz": "b626faf3275fcd196cd627e8a36c67721bae16a56f61cd080c79d137b3ec7737",
-    "dist/2024-04-29/clippy-beta-powerpc64-unknown-linux-gnu.tar.xz": "2c599d2dc719d69f67625f3c6573fcc4f1ea3266801557dd3892bdb7c761b4cf",
-    "dist/2024-04-29/clippy-beta-powerpc64le-unknown-linux-gnu.tar.gz": "0bc1f546fe0cef2b9516231ab608de68d55f72022fbc9ced5101b600e005f8c4",
-    "dist/2024-04-29/clippy-beta-powerpc64le-unknown-linux-gnu.tar.xz": "993294f2ae5202785ab242c1c6567df9c8ab1ef44ad35748c526b7fe854fb94e",
-    "dist/2024-04-29/clippy-beta-riscv64gc-unknown-linux-gnu.tar.gz": "210a4f0d208e0c8e13a57fb3b3e6c98ab5f620e4988d10a127ff1424ac1d5ca9",
-    "dist/2024-04-29/clippy-beta-riscv64gc-unknown-linux-gnu.tar.xz": "f10f7df41a13ee2ecdc25d60e697cba2342129a912ef20d8bfca5f611a9ec97f",
-    "dist/2024-04-29/clippy-beta-s390x-unknown-linux-gnu.tar.gz": "3e24d2af65f0c9667c9997ce091711b2be48e673de3707cddfd8cda455dfecc7",
-    "dist/2024-04-29/clippy-beta-s390x-unknown-linux-gnu.tar.xz": "0e7b8fbd0207489e38c78c2ae1aa0df4fcbdd84741aa50a86379e4d7ede286b1",
-    "dist/2024-04-29/clippy-beta-x86_64-apple-darwin.tar.gz": "9c0c47fd97ce72abcd6126315834c62aa7297fe09d447ee4cefa1eb46a116326",
-    "dist/2024-04-29/clippy-beta-x86_64-apple-darwin.tar.xz": "49dd65c5340fd804399edfa2402cf255fd9bfce1f4aa7fbb3c193c11bc03f8af",
-    "dist/2024-04-29/clippy-beta-x86_64-pc-windows-gnu.tar.gz": "6c1c3bdf097a1846ae08b098c555c0c5e9e9b646c744d6bb5a855789196b8bf6",
-    "dist/2024-04-29/clippy-beta-x86_64-pc-windows-gnu.tar.xz": "0a7319d1062f73af1c8f0efe6ad970d10d02259162c5bc84bb1f3a10f3911bcb",
-    "dist/2024-04-29/clippy-beta-x86_64-pc-windows-msvc.tar.gz": "52fef3f8a64fa58934a633bd4944e8ba9e15f2c2766d0f302dea1a6523864dab",
-    "dist/2024-04-29/clippy-beta-x86_64-pc-windows-msvc.tar.xz": "8fdbe7590e62ab68a2e463b14da2595e8c4592744f578a813f64d430ed7db4b6",
-    "dist/2024-04-29/clippy-beta-x86_64-unknown-freebsd.tar.gz": "509bf535622bd26385184ee0c17e4e27a5061a8aeebf5759f24bd578692b2f5d",
-    "dist/2024-04-29/clippy-beta-x86_64-unknown-freebsd.tar.xz": "2fcd10ada329ba7633616bebc584dca13f11c465e7cf513e76efeb0c3174486f",
-    "dist/2024-04-29/clippy-beta-x86_64-unknown-illumos.tar.gz": "ea8cea0d4a2379bcd0693f6174b25bc1f90a016dbe8280159cbb61d859806fb0",
-    "dist/2024-04-29/clippy-beta-x86_64-unknown-illumos.tar.xz": "5a243df8d1345db6bd18e4386ba628e6d302bce1cc572fb447cca4264fda3ee9",
-    "dist/2024-04-29/clippy-beta-x86_64-unknown-linux-gnu.tar.gz": "2ee560d3c1e306e103eb06d8e8033cd1489b3f6ff9df3bd8a95e25e977befa27",
-    "dist/2024-04-29/clippy-beta-x86_64-unknown-linux-gnu.tar.xz": "aaf6e54184a65ad6592bf03955a84ad12b561afd86064b1ac5fa03cf637052f8",
-    "dist/2024-04-29/clippy-beta-x86_64-unknown-linux-musl.tar.gz": "1b3877424a0a0eb507675a50e9d2c793f00ab85f6f12b1e27f871331070325b8",
-    "dist/2024-04-29/clippy-beta-x86_64-unknown-linux-musl.tar.xz": "6df5eaae5afb64557ba5c3a53ee3e56dab85455838a6044c7671c1180acfeaf9",
-    "dist/2024-04-29/clippy-beta-x86_64-unknown-netbsd.tar.gz": "1ac05ed7b607fff8b77ff203a663e9f4f2487779bc25e2dcd454cdf5b7583328",
-    "dist/2024-04-29/clippy-beta-x86_64-unknown-netbsd.tar.xz": "da502375b3cee8b254ab5999809f522692c2d1d90ea0544ad03c0ca514c65ef4",
-    "dist/2024-04-29/rust-std-beta-aarch64-apple-darwin.tar.gz": "2fdd35ca3b3e3d6f548f11c93337f5bf2e3c088bc78a79881e6f8e230b38b9a5",
-    "dist/2024-04-29/rust-std-beta-aarch64-apple-darwin.tar.xz": "bc16b3a1ab6ed69f0121a117c50cbcd201500dae4d72ad0dab148913d04cc529",
-    "dist/2024-04-29/rust-std-beta-aarch64-apple-ios-sim.tar.gz": "9375c786703c17baae1c2066f8d972ac316bc840e478ecd1b94288a1d428324e",
-    "dist/2024-04-29/rust-std-beta-aarch64-apple-ios-sim.tar.xz": "50d6818a8dd3ab7a3ddbbd7a062b538d9ff3ceb6eada031d1c22ab1dc7ba512c",
-    "dist/2024-04-29/rust-std-beta-aarch64-apple-ios.tar.gz": "56c3a01e8fd5c2ed75df811993b0b724709fb5473cc308ac09e7f5644468f751",
-    "dist/2024-04-29/rust-std-beta-aarch64-apple-ios.tar.xz": "3527d1f2c99c806479fb4b3801335dc921b514f171b82cd252cbbfc9ed30b163",
-    "dist/2024-04-29/rust-std-beta-aarch64-linux-android.tar.gz": "bf8cae7c66489f1aa27f1dea1b37f0d0ae514a6e21b93ff2dc6400dc88feca03",
-    "dist/2024-04-29/rust-std-beta-aarch64-linux-android.tar.xz": "46799f0bc1b3c13877f6cb732774cb3b33e0d8a081bfb56d0f877e79482aa1de",
-    "dist/2024-04-29/rust-std-beta-aarch64-pc-windows-gnullvm.tar.gz": "9f90fadab5104e1d415edf3b4edfaf7222f9f0d55f849851efdec74ffee16f8d",
-    "dist/2024-04-29/rust-std-beta-aarch64-pc-windows-gnullvm.tar.xz": "87ed6774202b18691bd6884df6944c7e9fe9c944b57a2837e7a7647518bf94e8",
-    "dist/2024-04-29/rust-std-beta-aarch64-pc-windows-msvc.tar.gz": "4a0692ad28f7f130b472ffa4aa766b745ba01fb75aa921f2da6622c9c68750df",
-    "dist/2024-04-29/rust-std-beta-aarch64-pc-windows-msvc.tar.xz": "a3d45962489a1e18a87e567cbbc8d3665f38809d0ad2ef15bcf0ff9fb9f470a4",
-    "dist/2024-04-29/rust-std-beta-aarch64-unknown-fuchsia.tar.gz": "c724f4eb135f73b9c79618f27a1ab35dc7b9d26ca62ed796accce68f9e747a66",
-    "dist/2024-04-29/rust-std-beta-aarch64-unknown-fuchsia.tar.xz": "8eab25782d16bcee75f86ecbb826346beb4a7525b220b45b3ba05a567c6d4391",
-    "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.gz": "33ab1f8410edf590570d7468dbe2ebb5a0907125bbc8d360a928dcb355f0d0e6",
-    "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-gnu.tar.xz": "d3d870209a55ac96391affaa347c04f48cf98c089ac5056f340b8bb38bcc8e60",
-    "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-musl.tar.gz": "4d2bb72b898c30a2fc8d5d3333c2e99a8e30c15891fab641b6a519dc9f0cb611",
-    "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-musl.tar.xz": "fa343e6b6110fcd0c5dae4287ff1a799de5d7e4a805dbf4e9a034bbaed2bf269",
-    "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-ohos.tar.gz": "f1ec4139783169fd83e1b0184518ed25d26cee7b21f196deecc74e83a1d78725",
-    "dist/2024-04-29/rust-std-beta-aarch64-unknown-linux-ohos.tar.xz": "d100be2f6f0346c4b1f5b41aec0c13a47426bf4d49127f2341c8332903e4e782",
-    "dist/2024-04-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.gz": "bab6051e1071a58cd126580f6644decf16edb4473fe4be6a34791610d820a294",
-    "dist/2024-04-29/rust-std-beta-aarch64-unknown-none-softfloat.tar.xz": "d9b68f06ff23629063e92dfc42aa3115a858238d368e4b52b35c1ea4491b1402",
-    "dist/2024-04-29/rust-std-beta-aarch64-unknown-none.tar.gz": "96804c2d9accd3242bdc22dad688b2ccee071952477b9c592f099377aee6c591",
-    "dist/2024-04-29/rust-std-beta-aarch64-unknown-none.tar.xz": "3fed6812d84bdaf787e85c37e23ba729b81a6d25a2b33fed75320e66e6641c89",
-    "dist/2024-04-29/rust-std-beta-aarch64-unknown-uefi.tar.gz": "8da5f301bff35fc067ec7cfb878ebfa5607af7dbc276a6b34a77404432c700d2",
-    "dist/2024-04-29/rust-std-beta-aarch64-unknown-uefi.tar.xz": "80d643189dc9af98b6410a01261ce6ad34b1325f3aebf3ff61fb43f1261b41ff",
-    "dist/2024-04-29/rust-std-beta-arm-linux-androideabi.tar.gz": "2e86b54b0d1f7fefead11d6383bdc80fe0a7b3ccf58381d2a731e6f1c62926de",
-    "dist/2024-04-29/rust-std-beta-arm-linux-androideabi.tar.xz": "9831a0270457cad2798b5ae4fe956c257c7e10ce5ad211793dc467577cdec29e",
-    "dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.gz": "f96bc303c0c2be9cf589f00aa63b2cf3fb8585ca9dd8860fe525821bfa1fe19a",
-    "dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabi.tar.xz": "e57a053b1c2bb6fad93dfaffedce7f48fa292196fc8ba6fd2f0c74dc810a13a9",
-    "dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.gz": "49b2cb2ba5296871b5fac5ad9a74a2891e8b78321078a455ba4a65e003bebd40",
-    "dist/2024-04-29/rust-std-beta-arm-unknown-linux-gnueabihf.tar.xz": "0f9c15d834a9d282a4018934759f7b48ef3d275e09679a68c5fd1b3f047d02e4",
-    "dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabi.tar.gz": "e59f92827241e670c1aa92b35235ad12340869d59327fb83084b5f4149acbe06",
-    "dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabi.tar.xz": "ad1cf96bb1fcceaa016e29e8ad34b4cfd711d2e0bd7cabb9cd7cc28abf64d894",
-    "dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.gz": "14a6d318af85bb9fa5c229e45a88a32a71f44ed02cd90a24bb67921eb64dee41",
-    "dist/2024-04-29/rust-std-beta-arm-unknown-linux-musleabihf.tar.xz": "ed6b48502ab9169818bceb300b4e6b4fd63366ad5808b047bf9988dae04c2729",
-    "dist/2024-04-29/rust-std-beta-armebv7r-none-eabi.tar.gz": "345e8a023be55e3b88a0c2677ea28c7bb4fcc5f3ab707638de76065c7592c2d5",
-    "dist/2024-04-29/rust-std-beta-armebv7r-none-eabi.tar.xz": "6d9b11d08f2d62611327a893b45ba07c36df11f077250496ab0881eb7ac84c65",
-    "dist/2024-04-29/rust-std-beta-armebv7r-none-eabihf.tar.gz": "a2ae1bf003a8a12b2ecb6bde9868a978820f184af523f0e4c3fc935edd509423",
-    "dist/2024-04-29/rust-std-beta-armebv7r-none-eabihf.tar.xz": "3d1dcf8308f9d4590b429f6abbf8f42f04496ab490ccf4ed8c9e381e6d886cae",
-    "dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.gz": "a54106d27e4ce97463e7867ceff9dd22ba456f840ec23229e6909b37d48ad554",
-    "dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-gnueabi.tar.xz": "e6abfaa0905a00efeaee85b9f93793bab93e2cf4e172c9d829c5ba85006c688a",
-    "dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.gz": "cbed18e5dc61fcecb2920affc3890c3b8ae46b7fe5a80b3288689e18d490f3f4",
-    "dist/2024-04-29/rust-std-beta-armv5te-unknown-linux-musleabi.tar.xz": "2b58bb0dd5cd2c5f7f93f4c6e9135090b931e0ffa27ff9efe2b8ff9fbbb7e48c",
-    "dist/2024-04-29/rust-std-beta-armv7-linux-androideabi.tar.gz": "6a371c2ececd349dfa76a02563069912fc91577ac4446d36c22f96723d7f5e9f",
-    "dist/2024-04-29/rust-std-beta-armv7-linux-androideabi.tar.xz": "9325daf41ddab02fa845971c10a5e0538a18c7bea14e66fa0f5f6fb16654c7ae",
-    "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.gz": "7f5ba76cfb7c85333c8dab76fb4ad3f12ddc254b95f9ee07fadb8e1270a4f767",
-    "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabi.tar.xz": "f853b7f929b7a309ed6c08ff8c57d583ce0ccb19270674fb30e63a873834dc87",
-    "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.gz": "0680005d0a12498b687afc583d4f36bd67d0877cd9d3323bfd2df50d15c27afe",
-    "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-gnueabihf.tar.xz": "a494b78fcad01c83df9522d460ac2d35d2d00736a921381f2c611dc516edaa16",
-    "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.gz": "cfa555db31b5470e878b0f53d86617e7342e8bf018fe62cb0271dfe13db95f51",
-    "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabi.tar.xz": "0a8ccd6d88cbe79a855111fbda45aa1a728de655b6927f3d429d901d2afc6503",
-    "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.gz": "eac53424001c884a540c42f0b68447349ec5d0601a030c060aaed76d54895728",
-    "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-musleabihf.tar.xz": "42d78fca62361ff28db5bc43bb01cef7af5c6f4ab2110fe6170c3dce4707aab8",
-    "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-ohos.tar.gz": "c88de9f2e667da73177fb9c9309d7f1f467e31c18e3ae50d722c71ec8dd876a4",
-    "dist/2024-04-29/rust-std-beta-armv7-unknown-linux-ohos.tar.xz": "24b3c04a42d511cdc8c6107b597be38981114f0574eced493d0e90fc748094bc",
-    "dist/2024-04-29/rust-std-beta-armv7a-none-eabi.tar.gz": "cd4ad182a098c61550265879ccc04733c39110827f7ef62eecfb8c120ae4ece8",
-    "dist/2024-04-29/rust-std-beta-armv7a-none-eabi.tar.xz": "8499a014dfdf448f474a58f148784c2eef245dc909587d876d2fb9ddc6a4ec3f",
-    "dist/2024-04-29/rust-std-beta-armv7r-none-eabi.tar.gz": "e8e1870e5b12b3d8643d712efb91eb86b2081284cada4a140c1526692ab183c4",
-    "dist/2024-04-29/rust-std-beta-armv7r-none-eabi.tar.xz": "d6029121eacc44bd4dcd9ef6dd3cd0d775cb6e9a3d99f3d62d746fcbf8981cab",
-    "dist/2024-04-29/rust-std-beta-armv7r-none-eabihf.tar.gz": "1e0fc42c3802e205130c01ca90f92d793c1c5427b34da66fe77b97cf67b4a5c1",
-    "dist/2024-04-29/rust-std-beta-armv7r-none-eabihf.tar.xz": "4c8cfdb11bb686111fa4842d13430c86d9d14ada30e9df334b3777fe899233e0",
-    "dist/2024-04-29/rust-std-beta-i586-pc-windows-msvc.tar.gz": "ff895c1b39b84587f10903f4be13d275b545e690da6761190d12c01acc25c6d8",
-    "dist/2024-04-29/rust-std-beta-i586-pc-windows-msvc.tar.xz": "fdcbcff7b740235bb16e44174fff9080a7c0a31be358c8abc41805c02c20c3b2",
-    "dist/2024-04-29/rust-std-beta-i586-unknown-linux-gnu.tar.gz": "6b227f3b9001e148b66b7001f753a6f88fef9677e39d8fcf4d9c35fe8d345568",
-    "dist/2024-04-29/rust-std-beta-i586-unknown-linux-gnu.tar.xz": "1e29297beb8de3778ba958731294823d9a93aac1e0d8833abc5aa99e2935965b",
-    "dist/2024-04-29/rust-std-beta-i586-unknown-linux-musl.tar.gz": "26481ad5f22a319830d42f69b1c0195bd65900ebe112e659432334b3468f3d0e",
-    "dist/2024-04-29/rust-std-beta-i586-unknown-linux-musl.tar.xz": "c8a837e0d9da8ad976fc1539541c085365aac9dd28b34e4a289d38a823d1b065",
-    "dist/2024-04-29/rust-std-beta-i686-linux-android.tar.gz": "f05e28a52f17e22f36ffc70018012a1fe6a07f4b461e774b36464f32bc8f8dea",
-    "dist/2024-04-29/rust-std-beta-i686-linux-android.tar.xz": "f9501b2691c51e54a6f4cc6fb72e41901eb551d3a7be5f82a94ce2d3e217828b",
-    "dist/2024-04-29/rust-std-beta-i686-pc-windows-gnu.tar.gz": "8d9a782d4f7450bca536aab45147c6ef08bc3847b43fdd171c6449e29762eda0",
-    "dist/2024-04-29/rust-std-beta-i686-pc-windows-gnu.tar.xz": "4008712e03fb6494eaba3d79051c5e3fdd93d4c52ae8d86cf8f344b5f051cbca",
-    "dist/2024-04-29/rust-std-beta-i686-pc-windows-gnullvm.tar.gz": "cfb23242e495834a3d0f7ffa3da4a0b206dcae35872b1455b11faeee5511ba5f",
-    "dist/2024-04-29/rust-std-beta-i686-pc-windows-gnullvm.tar.xz": "95415742c0171945ffc2b67c913ebd1330e29634af238f5ccc843a965340374a",
-    "dist/2024-04-29/rust-std-beta-i686-pc-windows-msvc.tar.gz": "e9354d69e39ecfac1d2928664d17d73f808256a4076b849171a9667705c0aa08",
-    "dist/2024-04-29/rust-std-beta-i686-pc-windows-msvc.tar.xz": "a34bb0a91170d84195f35ba52afa4c9be8a2f2706dbeea02bd6e8908e08ac65e",
-    "dist/2024-04-29/rust-std-beta-i686-unknown-freebsd.tar.gz": "d65f286de399ccc9e9acaf7a4dc4f885357c750231d54a144ba9a59181814f11",
-    "dist/2024-04-29/rust-std-beta-i686-unknown-freebsd.tar.xz": "4c93a7da70a69b2ebbac01df64af16344e523d16470b29e57237b1d0925f7721",
-    "dist/2024-04-29/rust-std-beta-i686-unknown-linux-gnu.tar.gz": "1b978bfd1a9234be7ef197c8c98c5a6b625f6fbb7b0fca58695986768bdca176",
-    "dist/2024-04-29/rust-std-beta-i686-unknown-linux-gnu.tar.xz": "98d4eb5b89a593c8c4f86244c9a7c737d9c18c0168aebe5923b8d9145adcf89a",
-    "dist/2024-04-29/rust-std-beta-i686-unknown-linux-musl.tar.gz": "dbf9b3c5b54b3eb0727f976f5632c5b0fcb2f90ac7453962d6cef20f7dae4284",
-    "dist/2024-04-29/rust-std-beta-i686-unknown-linux-musl.tar.xz": "f209ade093753342dda6e710ee832a538dbdaa08a24d606f9a2a1bc59b83da29",
-    "dist/2024-04-29/rust-std-beta-i686-unknown-uefi.tar.gz": "3c3ca7f34569b2c70c6b223754418a535dd7dfa087ab6e28ed2ec78d20065887",
-    "dist/2024-04-29/rust-std-beta-i686-unknown-uefi.tar.xz": "72a7cd0f430ab40d80e93f409b8e26a181010ab4bb75d151e829d51ccdcf8c62",
-    "dist/2024-04-29/rust-std-beta-loongarch64-unknown-linux-gnu.tar.gz": "b7dfa59bb05cf806c87854d6fce5ef0f160697052fdf6e5a0cad121499108608",
-    "dist/2024-04-29/rust-std-beta-loongarch64-unknown-linux-gnu.tar.xz": "88bc22f68bab3367cdfa91676418ce1ffc0ec002afb32aed7def880bdd4be402",
-    "dist/2024-04-29/rust-std-beta-loongarch64-unknown-none-softfloat.tar.gz": "d61019048b941064a99d19e46ff3236a88a2e8fcfb963cedd1d9d1c47963c170",
-    "dist/2024-04-29/rust-std-beta-loongarch64-unknown-none-softfloat.tar.xz": "7474bda08134c676d74afe5263317af3f271963d8ceaa5efbfa1b657f885c572",
-    "dist/2024-04-29/rust-std-beta-loongarch64-unknown-none.tar.gz": "e089c77d433d838ca02d7531d6f4a1770fb4a0568acbd96c8f43034d76f2990b",
-    "dist/2024-04-29/rust-std-beta-loongarch64-unknown-none.tar.xz": "364ae6c89c7a930098286e55193d2f5ee3d5ea80b7cca73046e41725f4a8a2f9",
-    "dist/2024-04-29/rust-std-beta-nvptx64-nvidia-cuda.tar.gz": "c17bfad87d16f3a8d26646525dc59a352718db9e7572acb583b68a18cfdc338a",
-    "dist/2024-04-29/rust-std-beta-nvptx64-nvidia-cuda.tar.xz": "f5c4ecef1c08d19ba6fddbd359a0ce94e46888021cae057fce969276026d086c",
-    "dist/2024-04-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.gz": "3e7e13b0d2e804d228e1e3a9dac0205d294ae29dcc37132f15fb1e218861eb39",
-    "dist/2024-04-29/rust-std-beta-powerpc-unknown-linux-gnu.tar.xz": "ea31b7678e6f64c2f9c28a9af120be04ed6f2a25a496e40afbf6e9aa0dd20b60",
-    "dist/2024-04-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.gz": "f0e1b314c3d5ad1676c68c112581dce62fa06ad557cd5f61034e147b064ed270",
-    "dist/2024-04-29/rust-std-beta-powerpc64-unknown-linux-gnu.tar.xz": "8ab7bbea6e2f72df1286facc7d306d01809a4dd9f8901dfdec7e50b594658d49",
-    "dist/2024-04-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.gz": "48f6abda1c7dac185858744aa2cdc3513cdfb6552535282ee83cf9c5365573c7",
-    "dist/2024-04-29/rust-std-beta-powerpc64le-unknown-linux-gnu.tar.xz": "d920d97f15b56ba6ea81e08b3c29dc7f44f5f30b7513c53446edf95843c332af",
-    "dist/2024-04-29/rust-std-beta-riscv32i-unknown-none-elf.tar.gz": "0a198a770f6e6043e923b0ab1a508fd8b190612d0370c33c8dd2c5f63b6f19dd",
-    "dist/2024-04-29/rust-std-beta-riscv32i-unknown-none-elf.tar.xz": "424a93313cfe2d85acf956be3d9ac71ea8e34ee61617a550ad6ff5360e1dff52",
-    "dist/2024-04-29/rust-std-beta-riscv32im-unknown-none-elf.tar.gz": "2e2b0a8e41f4ea774d665d6248cbc2fdbe3e582206efeb87d250786ebaad0b1a",
-    "dist/2024-04-29/rust-std-beta-riscv32im-unknown-none-elf.tar.xz": "2da372c091017b7096e473e5c7016a504d2e041e14173d2520086cb43e0a615a",
-    "dist/2024-04-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.gz": "69d3b21403181b2df14243816388169db2466477ec34bcca5693fb017703686c",
-    "dist/2024-04-29/rust-std-beta-riscv32imac-unknown-none-elf.tar.xz": "281b9c20f8641a3d1b349e762b7f713fb0b91da0d21eec798e639e36a0ea3dab",
-    "dist/2024-04-29/rust-std-beta-riscv32imafc-unknown-none-elf.tar.gz": "dd9bfd3fd8446d35180fe781139dfb4e04dd658b112eb2a749e8f4aea14f0271",
-    "dist/2024-04-29/rust-std-beta-riscv32imafc-unknown-none-elf.tar.xz": "b1366375e0c5f53da581741dec91972b0c46d7d466052539207e8feaab0ba3ec",
-    "dist/2024-04-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.gz": "7c6650d8cf8abd51547010e8211af3ef3195099ef43a563460ad4780de20ba17",
-    "dist/2024-04-29/rust-std-beta-riscv32imc-unknown-none-elf.tar.xz": "bab46f3c0078ce346de563bb7a248ca92f15dbdc73bf5a3bc520486118442320",
-    "dist/2024-04-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.gz": "01735b4ad5bc0a53087dd0ccaef2cf174b27e45bf4d2e3c15e64f7522f059c63",
-    "dist/2024-04-29/rust-std-beta-riscv64gc-unknown-linux-gnu.tar.xz": "0bb272c2c235583ed3e9ec151b3bfc601f8cd07822c2fe47a1258b358be507f0",
-    "dist/2024-04-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.gz": "b2c7f8ee0efe6d0812e4b5dd0979f60f105b84d34d4f600ef75f2eacd954893d",
-    "dist/2024-04-29/rust-std-beta-riscv64gc-unknown-none-elf.tar.xz": "0d5301fc553a6911af6643ab7f57b6438bf649ffcd050d486278c0c5fe38eeba",
-    "dist/2024-04-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.gz": "0d1d35ecb88ee717720ad8e74bd5b602fd6011fe321baddb939f3b161e9cd8c5",
-    "dist/2024-04-29/rust-std-beta-riscv64imac-unknown-none-elf.tar.xz": "a5cf0b98596e68e6f72be2e83c61b8aaa19ead42f248ee2408a3b8f4e97a6657",
-    "dist/2024-04-29/rust-std-beta-s390x-unknown-linux-gnu.tar.gz": "629ed749cdae110668ad9ddbc5c61e99e8d400f3dd0981146c3820deadc360f6",
-    "dist/2024-04-29/rust-std-beta-s390x-unknown-linux-gnu.tar.xz": "192819438ed27a565cdb67b51d2f5caeb6ae258de86191d6922574327f132acd",
-    "dist/2024-04-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.gz": "84286f6cf6f00f3c92dc881f64a31e1ec5910102d8d3d4faf6fc7e2ddf1544a7",
-    "dist/2024-04-29/rust-std-beta-sparc64-unknown-linux-gnu.tar.xz": "304b5f876b47dcbb7c3483c49295b822e8ba83234bb568ce67896ae4773ae2fa",
-    "dist/2024-04-29/rust-std-beta-sparcv9-sun-solaris.tar.gz": "25062159b859e21dda76ca22d4a31d3aba4fcdb0def78bc5b5cf9887c07c1be9",
-    "dist/2024-04-29/rust-std-beta-sparcv9-sun-solaris.tar.xz": "5d557ee86457f288462603fe53bcc2e092d84faee543659419fa68c1bd88f554",
-    "dist/2024-04-29/rust-std-beta-thumbv6m-none-eabi.tar.gz": "a9663048aad82ef832b2cf82fa9fb94be047f77e283e8aa3e2df6ad957d0782d",
-    "dist/2024-04-29/rust-std-beta-thumbv6m-none-eabi.tar.xz": "4c4b703a846b4123d09c1eace6322e82784a004b278f1f3b1ca1279e96207f18",
-    "dist/2024-04-29/rust-std-beta-thumbv7em-none-eabi.tar.gz": "32907c33f240abb1cb17ac438da42c5fa3932b270ad08fd6914775c5b59a02f5",
-    "dist/2024-04-29/rust-std-beta-thumbv7em-none-eabi.tar.xz": "112583227d2b6abfef6eeb78d980bf2efef392f3b66e433c4959a642d72ffc7b",
-    "dist/2024-04-29/rust-std-beta-thumbv7em-none-eabihf.tar.gz": "7ba0084527a18479c4b6f6a0dba8ae23a0ed50e9fc5fbfce23cae1babb5a1e12",
-    "dist/2024-04-29/rust-std-beta-thumbv7em-none-eabihf.tar.xz": "49eb4e2efe3a76713ce1fecacaf915717eeed8552912b92895c7fee068a85a36",
-    "dist/2024-04-29/rust-std-beta-thumbv7m-none-eabi.tar.gz": "518a532b52f2dad2825158614cd00b12aac6c6e1983a1ad53e2b0e26d1f1b845",
-    "dist/2024-04-29/rust-std-beta-thumbv7m-none-eabi.tar.xz": "2895e5796a29fd016462694d880e38eb191cb92c9bdb14414c1d6e63b23d3394",
-    "dist/2024-04-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.gz": "2af590c063344c4c3f65d704fa255232b5f5954872d03c4c55d48662cbe6bb17",
-    "dist/2024-04-29/rust-std-beta-thumbv7neon-linux-androideabi.tar.xz": "a09df5f38183d9fe6116c807619f812410763ddedf06055bfe8040b5794104d3",
-    "dist/2024-04-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.gz": "eac22c4972bde3a57cf2ec4e31b43db3c4b7d961ae31475d8942e898c07640cc",
-    "dist/2024-04-29/rust-std-beta-thumbv7neon-unknown-linux-gnueabihf.tar.xz": "104f2c6490e30cc47833edbd806c2efe6256d1194600b2278339612f94704d45",
-    "dist/2024-04-29/rust-std-beta-thumbv8m.base-none-eabi.tar.gz": "b3c9c9d7ce8c1db6f20e8ede542e67aacd6047c52882a5d06c4f96a40a7304d9",
-    "dist/2024-04-29/rust-std-beta-thumbv8m.base-none-eabi.tar.xz": "76bfb114bc7674792934a4892d2db41fdc8f5bd30c3aa96c43e8055199157476",
-    "dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabi.tar.gz": "1308335fe80dcafaba511ee589959d461145533de5f76118fee29a7e9a15841f",
-    "dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabi.tar.xz": "cb8acdb8920983c03b9495cf3506a3014384b4d2f6a53e7907924d38a0baf7f0",
-    "dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.gz": "9dd2e5ce7534ab4fbb93ff652196e877f4e9eea3863920c3d34a05d9a3598c81",
-    "dist/2024-04-29/rust-std-beta-thumbv8m.main-none-eabihf.tar.xz": "4b6e962facf7c54846965a8d6880e4a980804459151f2e22ac5af79bc79e26bb",
-    "dist/2024-04-29/rust-std-beta-wasm32-unknown-emscripten.tar.gz": "731603392b6e3d36b3a4956928d084e293ef18c8b8593efa756e753a2a309709",
-    "dist/2024-04-29/rust-std-beta-wasm32-unknown-emscripten.tar.xz": "8b681b3af47855eb63c4ffe06a2bc6bc4f365354ffbc171ce8cbd8c2a3588a07",
-    "dist/2024-04-29/rust-std-beta-wasm32-unknown-unknown.tar.gz": "7b87e59391493c3147c03794061111e25bdae669aea58190a951cdef111e75e0",
-    "dist/2024-04-29/rust-std-beta-wasm32-unknown-unknown.tar.xz": "d15eaadb101027906c2fce15b95a3f820bdbc4cf145b705bafc2ac5291289c3b",
-    "dist/2024-04-29/rust-std-beta-wasm32-wasi.tar.gz": "07390ec742b79ec11b2c3ec65f60efe5d7c616f50c33058fce346f6e9ad21af3",
-    "dist/2024-04-29/rust-std-beta-wasm32-wasi.tar.xz": "79e34d46621c298cadb98c00ce3b25d97474aec300d85255153b47e21b7bb744",
-    "dist/2024-04-29/rust-std-beta-wasm32-wasip1-threads.tar.gz": "b916dc9051b0278f820ea0b093db3ecae2e27de641ef67a9b508df75dc92c938",
-    "dist/2024-04-29/rust-std-beta-wasm32-wasip1-threads.tar.xz": "2867922a39da3b02ebdb93fb78b010695daf468f87485ad8ab79c7f3eeb18b11",
-    "dist/2024-04-29/rust-std-beta-wasm32-wasip1.tar.gz": "792b718c0a72e97ba85a17ba67ee09e55b85de829fe4021f828ce54ff8cb31e0",
-    "dist/2024-04-29/rust-std-beta-wasm32-wasip1.tar.xz": "abff86499119bddfeda9059004549941dbcd3d911702d4a9c198b94f60e60f4e",
-    "dist/2024-04-29/rust-std-beta-x86_64-apple-darwin.tar.gz": "0bcc7698efafb42a37f20815f5660e39829a42a2776304e7129d0a4ec0c7520b",
-    "dist/2024-04-29/rust-std-beta-x86_64-apple-darwin.tar.xz": "c437626e250b0d06c05dc828ab81d0d2c543ffce4b100567910508974ea50045",
-    "dist/2024-04-29/rust-std-beta-x86_64-apple-ios.tar.gz": "7c98c9f491bfc837111769a45c10ce2f1ef73c22377158ef9ae80b38034892c0",
-    "dist/2024-04-29/rust-std-beta-x86_64-apple-ios.tar.xz": "f4bda724e6e382e02ddf4e4e7a479120420666a5a1ad3c87a85d4d3c763f2cb2",
-    "dist/2024-04-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.gz": "01efbb2e48045318e18bfc7b6c190b461a219e81fc1cca6c855bf0c658aef556",
-    "dist/2024-04-29/rust-std-beta-x86_64-fortanix-unknown-sgx.tar.xz": "9bff316c6d2fbb3c0889f9ffe4eae496b293fb3afaf8d597155e6badbf0c6a8e",
-    "dist/2024-04-29/rust-std-beta-x86_64-linux-android.tar.gz": "5da713547a8af2c86da7db5d8aa4c27188dea1089fded81ffbbeb0f78952a10f",
-    "dist/2024-04-29/rust-std-beta-x86_64-linux-android.tar.xz": "9d6a45d6af395360c63ce97bcfc2f9a2967c708afcd979f17fa447239703a92b",
-    "dist/2024-04-29/rust-std-beta-x86_64-pc-solaris.tar.gz": "d1a71110bee002c8edfbcc00e0f5eede5afa005b09944bb2cde469c658049e70",
-    "dist/2024-04-29/rust-std-beta-x86_64-pc-solaris.tar.xz": "6b8d18c83b9fffdddf9e55c807dc7d5784cc6d7ae90a57c29b87d707f0656964",
-    "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnu.tar.gz": "28921ee14426f54aa09523547516437130654b2d9814120d286f209666c88533",
-    "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnu.tar.xz": "7c3125cce30978ca2619e9aab150cb5b9b2535fbb6274d4ac1b1d4342c7b0220",
-    "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnullvm.tar.gz": "ee5c237f092f8a4ba797c4c7769dfd4da81b5c86d2f4b88704d127642d222a22",
-    "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-gnullvm.tar.xz": "30c84b04bd2d4d33abf1875cfee5f227ef6484edc67b3cc4c9c96d92c8406d6f",
-    "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-msvc.tar.gz": "81274050e72c5a8ffdead83f7be62434f35a65517a1b3c6f7d9d14d0d59da710",
-    "dist/2024-04-29/rust-std-beta-x86_64-pc-windows-msvc.tar.xz": "215e20c78a2a4edf9b8368a29a09af5f4cf8d0edd1995de3bbf2eff01127cab7",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-freebsd.tar.gz": "340131cba121827a9753e19cb3a4b9ba2ebe30569fb20d7f9300b4dbe2a15cf4",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-freebsd.tar.xz": "69626178bc5309afc8a02c941bd77e70e1aa6917ffb6bf0d67a57d921b5c664a",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-fuchsia.tar.gz": "22c6c90533dad3a731ad8a6696e6cdc1b15579e25c658fa2b094185e1893934f",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-fuchsia.tar.xz": "30d7ef6684fa98e28037b69d4220cba40489c23e80fe7793c98b388dc161757d",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-illumos.tar.gz": "9d7192d32eaa6b6ccb0f615da0f4cd80827ba6484eabeaf401d8217678f1e313",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-illumos.tar.xz": "7a3fb35e0bb252d5f90773136d1417c26d5601beadb77d6da6f5ad3081977f07",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.gz": "e987635519c1edc8a1d147ca4a86283637e4dbd0a49736b01d605e45a3a14e8f",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnu.tar.xz": "c3ab6b97dccc0038c68494b03b6d444d534e447226a2b2e140af54c94fca0b2d",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.gz": "72e8113687be8f947c50befb42b0957dd564f01693cf4d68d749a9e074032ada",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-gnux32.tar.xz": "867b24f33b19f40727c71818c8a002718d44d4cd4ceca44314331e19c1adc1a4",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-musl.tar.gz": "f9b0fd9605bd4e264f5303bd740d9a0195bc147132969965b221f9da0d7875bf",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-musl.tar.xz": "022dcf4887df41d776ba2666858b9aaab479758134a71f7c6b2172ed7c1a1752",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-ohos.tar.gz": "b5ff4a0ecd7e0f71a9557b6096bb907e5cbc8982431f0d9b01d8e1a895d8b37e",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-linux-ohos.tar.xz": "e40d5bfb46aadf6faf849df548154db3f35f356f8b98037a056802a235922b8a",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-netbsd.tar.gz": "57cfb1fa472dd9c01fc0caf605a55b7248375d616acf84ec12f6430d5e07e2ee",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-netbsd.tar.xz": "e4121f060b917c811d971e85ce02495e83150ddcceb2204615edff24bd55bfa6",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-none.tar.gz": "d63559803c8eb47e0d10d9f3a2284477b570a2536bb541762774271451e1f0ce",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-none.tar.xz": "5388cf8ecaa234d507e505e8c6d433c5de8811b2717aa254e4caac9f4aa6cd97",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-redox.tar.gz": "0f027163f37618df4330ecd82afece432b0a509ab20333d7b787c0d139ea89c2",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-redox.tar.xz": "b1c722e894b145c2183183fa58762c64402fac077419dc7874f8b08eee665651",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-uefi.tar.gz": "24e2ac0d44619ef9b76cb1af6178103d65ab12e2677b366e8aee0604798fe5f1",
-    "dist/2024-04-29/rust-std-beta-x86_64-unknown-uefi.tar.xz": "1d8a45f1bfe6650edc5ddfc8683190eff5a74384abcb2f73eb3d1e88d566ccfc",
-    "dist/2024-04-29/rustc-beta-aarch64-apple-darwin.tar.gz": "ea113c567692d54983ab6c376761651b6dcf9bedad5b5d822d28c0d0d0733cf2",
-    "dist/2024-04-29/rustc-beta-aarch64-apple-darwin.tar.xz": "e36363f1ea531d2fd563f471758e387de37a34e7ef6f4c12175979657333c5b4",
-    "dist/2024-04-29/rustc-beta-aarch64-pc-windows-msvc.tar.gz": "52d77d540fc3f83d82f35f358ccd9055fb75453af3e3bee4b11636742559db13",
-    "dist/2024-04-29/rustc-beta-aarch64-pc-windows-msvc.tar.xz": "843c56f5431c1feda85ceaeef0daf988e8ae020b3556326fb1f75ea7968bf2df",
-    "dist/2024-04-29/rustc-beta-aarch64-unknown-linux-gnu.tar.gz": "ba2fe37dda1a487a2c75151895f4f6e886e9476a992272ce26e9b5fd7adb11f9",
-    "dist/2024-04-29/rustc-beta-aarch64-unknown-linux-gnu.tar.xz": "ccb7be3935de1920509d2061d38f92f1fb8d2a5dd6cef392492242a929363fa9",
-    "dist/2024-04-29/rustc-beta-aarch64-unknown-linux-musl.tar.gz": "40636e0936bd311803317825c5fb6b446cdb5536ada1db097b567df04a86d7dd",
-    "dist/2024-04-29/rustc-beta-aarch64-unknown-linux-musl.tar.xz": "804ef68f24bc0ba5150177d8b8515daa54aa82fcb61472385ef1a1d897c5c3e1",
-    "dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabi.tar.gz": "a320c2869d1d2c92b698397d4467c8498cad9481f38d28ac810bd165399ca46b",
-    "dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabi.tar.xz": "7ce92211d87068d9c223806929adc34ca611a1321cd58b5bd81aabb0ec3ff085",
-    "dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.gz": "79c16b902884301882d16be36fe75ecb32a8e49abde0038ce21cfbee883c2c3a",
-    "dist/2024-04-29/rustc-beta-arm-unknown-linux-gnueabihf.tar.xz": "9384eb9bdbb585b414b6c04c592a79e90a0c0ebfeeb970e5e1b920cb638807cc",
-    "dist/2024-04-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.gz": "ff99de5b819a4fb9adce9386a309b9841bd33632eb7d5079415a6ca6fc86b9dd",
-    "dist/2024-04-29/rustc-beta-armv7-unknown-linux-gnueabihf.tar.xz": "55635cde13af11dd8cc007d2e0499bfee493bdfba87b6efd7b1fa4115f5728dc",
-    "dist/2024-04-29/rustc-beta-i686-pc-windows-gnu.tar.gz": "de82ac745275f069225b84574ed145afaf9f54abde5246592e49d5d1cf40cac1",
-    "dist/2024-04-29/rustc-beta-i686-pc-windows-gnu.tar.xz": "a8a7bf64d33c95a2f94265fba8dd9ac50bbb727f4bc3e79be5bf61212cb5d22b",
-    "dist/2024-04-29/rustc-beta-i686-pc-windows-msvc.tar.gz": "88967a99c993d6e0c3c7948308510644286ac826266dbd3d89aaa083100711db",
-    "dist/2024-04-29/rustc-beta-i686-pc-windows-msvc.tar.xz": "1804f75786482946258ff0e827274357c49e90a7f2f568add7353249f2ab78b9",
-    "dist/2024-04-29/rustc-beta-i686-unknown-linux-gnu.tar.gz": "3cb7e02c61d4a21d8289289b874b25e8b020c1d553e5af950160bffc14f51c18",
-    "dist/2024-04-29/rustc-beta-i686-unknown-linux-gnu.tar.xz": "2ad4b1311a0e39c359798375912faa91b4e13cd473bd59efd1e4f721777d254f",
-    "dist/2024-04-29/rustc-beta-loongarch64-unknown-linux-gnu.tar.gz": "ab19efb741a127615b9022dedf1d895b53c69740cc3da745f9b9888bade9d98b",
-    "dist/2024-04-29/rustc-beta-loongarch64-unknown-linux-gnu.tar.xz": "492cc11d54df410c2547890803930fc65950e6b81ced512e24bef56c3e70f3d2",
-    "dist/2024-04-29/rustc-beta-powerpc-unknown-linux-gnu.tar.gz": "c5a631a41f417336f3f65c85adefd1fb0bacc02465485f37d29fc1223c9f6cec",
-    "dist/2024-04-29/rustc-beta-powerpc-unknown-linux-gnu.tar.xz": "0701183b615d9eec9daea724d4cd8fa98dede2260cfb6b137d6cbf8ad6b29a4f",
-    "dist/2024-04-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.gz": "cb70e92d5275862b500614d79eaea3d19319b96798f4850cb19dea9a8038a651",
-    "dist/2024-04-29/rustc-beta-powerpc64-unknown-linux-gnu.tar.xz": "908cbe562d82cca1bf176fdc99af867966ea423d244c4a50e14bad19f6878201",
-    "dist/2024-04-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.gz": "8580a3eb6d6df1774f4b6ca06dc1195c42b1e2a463488a5d851e99b0ca6d0249",
-    "dist/2024-04-29/rustc-beta-powerpc64le-unknown-linux-gnu.tar.xz": "2627948036e905f2e280663c56c86c172e2b0d057311ade7ca238953b7e0c36a",
-    "dist/2024-04-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.gz": "526e4f129fdb4b2c8f4317c57105a09ff03e71771d6d6bbbc9380917b5440d71",
-    "dist/2024-04-29/rustc-beta-riscv64gc-unknown-linux-gnu.tar.xz": "fd9dcf60838376478d7cc505ec7fc39f86f9d042646a3b836e9c06825927c7eb",
-    "dist/2024-04-29/rustc-beta-s390x-unknown-linux-gnu.tar.gz": "664c1255a9435d1ad086329a3c215974b9302d481762240cc9d0328d9f1b8c9a",
-    "dist/2024-04-29/rustc-beta-s390x-unknown-linux-gnu.tar.xz": "a585ce7684e4174f03adb09df17221e1729e8179dbc91b9a0f8813c3ecc0822d",
-    "dist/2024-04-29/rustc-beta-x86_64-apple-darwin.tar.gz": "59a1d91009b506a5bce3c276993cb8acfd71f73d01f9eaf4195b36114ac822c3",
-    "dist/2024-04-29/rustc-beta-x86_64-apple-darwin.tar.xz": "f86f3309cf2784b076f14e7da9e921c294a7701ea92d378c609061deccbc6bff",
-    "dist/2024-04-29/rustc-beta-x86_64-pc-windows-gnu.tar.gz": "f5c074461409b33a9791325d4014e6861ad36f99b9e48e54ecceb73986450be1",
-    "dist/2024-04-29/rustc-beta-x86_64-pc-windows-gnu.tar.xz": "045431eec6f839b1c40b5a75c5000f80bd6351274a59b29d962833495324ecb6",
-    "dist/2024-04-29/rustc-beta-x86_64-pc-windows-msvc.tar.gz": "a3abfb68e60544170f47209bbf048f1374e5bb75901a529e2ac2f315758155f8",
-    "dist/2024-04-29/rustc-beta-x86_64-pc-windows-msvc.tar.xz": "398c41a3219781c7cf1a907406506526b672abca6d3ab59c30556390a5f992c9",
-    "dist/2024-04-29/rustc-beta-x86_64-unknown-freebsd.tar.gz": "38895e615efd0bf75ca14b0ab0a085527cca64fae17631d1780a8f51acd26d17",
-    "dist/2024-04-29/rustc-beta-x86_64-unknown-freebsd.tar.xz": "786f40030dbe5e6897aafe4bda44770920b2010b93fc5ce86574774e531e2eff",
-    "dist/2024-04-29/rustc-beta-x86_64-unknown-illumos.tar.gz": "7003cab7650dae7e3d29032422a57782a2c146024c437a6466ae1dd2b61a6618",
-    "dist/2024-04-29/rustc-beta-x86_64-unknown-illumos.tar.xz": "bed3cc10203e8bd4d43b6245928c8a607acc5b6e633635caea45eb4eef4bda56",
-    "dist/2024-04-29/rustc-beta-x86_64-unknown-linux-gnu.tar.gz": "84cdea91c9f1e848ea17f554229ca80d18d093fc609641d8f003c4f2d4871866",
-    "dist/2024-04-29/rustc-beta-x86_64-unknown-linux-gnu.tar.xz": "a20fce7512f7c8cc6230a0f63f12855b04370d25e621183f71aa444c90c36b4b",
-    "dist/2024-04-29/rustc-beta-x86_64-unknown-linux-musl.tar.gz": "87e0c484ade99efab57c655ef96dbabf7a02314540575b65a14372ab5496c36c",
-    "dist/2024-04-29/rustc-beta-x86_64-unknown-linux-musl.tar.xz": "469757d8f35c9f4210aefd2ba660ee249e4409d47b908a6c68c1e650ee81ae67",
-    "dist/2024-04-29/rustc-beta-x86_64-unknown-netbsd.tar.gz": "4a38000480fe78fd5da7f9b71d36f296a6ae103254d932c4de6b902354e86bbf",
-    "dist/2024-04-29/rustc-beta-x86_64-unknown-netbsd.tar.xz": "45945d6af237fe4c91fde7db02ca19e99bac56a911b8db79be9b6ab8bb3934e1",
-    "dist/2024-04-29/rustc-nightly-aarch64-apple-darwin.tar.gz": "0b07375a9a6507fd4932a05b5aaf28ed349fe2040103f1cb69c8a2494437258f",
-    "dist/2024-04-29/rustc-nightly-aarch64-apple-darwin.tar.xz": "143bd7ed3ca7b913ddd0cea7cda8d1a0e4c29cc2ccbb7d29f0e45c2a87c3ec46",
-    "dist/2024-04-29/rustc-nightly-aarch64-pc-windows-msvc.tar.gz": "9404c111b91fd092367b88adbc37dce10a98c443bd8d9e13a860e1fb4e3af96e",
-    "dist/2024-04-29/rustc-nightly-aarch64-pc-windows-msvc.tar.xz": "f9f432907c276edcae5ad8ade0264f3c03109be02e791a814edc8ad3d229637a",
-    "dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-gnu.tar.gz": "33425c90427424f0b30fa2a6331a3b59c680f1c1bd0d8845d7e6bc1e2f80292d",
-    "dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-gnu.tar.xz": "03792890c64c72f30143849894b15f0eb3d6ad735fceede9092abd900ee733e4",
-    "dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-musl.tar.gz": "cf6f2bffa0db1b4b9b8e95801bf415dcce413f902e26f4c1831dff1a00752b99",
-    "dist/2024-04-29/rustc-nightly-aarch64-unknown-linux-musl.tar.xz": "9192fdb668df8d4cab776623db7d01e35af42fea94098c1d4ba53190825d81a8",
-    "dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabi.tar.gz": "a174e7e08da2abc6b84499360670188f5cc61b6d055967e04bf602ff3d831f45",
-    "dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabi.tar.xz": "5a59811027586863852b15fc2b603e7e69b19841f4c10d2527ef1fc5b77d8af2",
-    "dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabihf.tar.gz": "645bb5dd7a96bb9292b9956cb9705e9aed2408e47728f245564f1f7404ede783",
-    "dist/2024-04-29/rustc-nightly-arm-unknown-linux-gnueabihf.tar.xz": "1fe34911b082c3a5ca4f24656675c095d2cf56f8005be9ca2517d0ef7d0a2b37",
-    "dist/2024-04-29/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "f2d6403d81bb0afe2e14956828987a0bb044c95f2d9566e1d792dd922dad7914",
-    "dist/2024-04-29/rustc-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "d93fdafcbbfd50c88c3f4feb4c68b053882ccae02c45e1615aeeae5a86f4aa98",
-    "dist/2024-04-29/rustc-nightly-i686-pc-windows-gnu.tar.gz": "a9e997b03559b3dfa2a0eba6ed7a142d7651ea7f4ba4e788d9de807b50558e58",
-    "dist/2024-04-29/rustc-nightly-i686-pc-windows-gnu.tar.xz": "4412b5fbfab8c5b31e57cf8c4ce9a9d13cfc9c0a8174ea1fc8a7c05281e1cb54",
-    "dist/2024-04-29/rustc-nightly-i686-pc-windows-msvc.tar.gz": "1725c41500dbf6bea554f3d4acaba70167f0e89087aaa3eb3c0f8a99047c55c4",
-    "dist/2024-04-29/rustc-nightly-i686-pc-windows-msvc.tar.xz": "27db022494afebbe05605f134191e8b2e78bfdeaa638d4215174038ca9dd2fd7",
-    "dist/2024-04-29/rustc-nightly-i686-unknown-linux-gnu.tar.gz": "dc1a05d49b773dba06808c1c50653ecac506b3433f0f6dfa307109a7c621cc1a",
-    "dist/2024-04-29/rustc-nightly-i686-unknown-linux-gnu.tar.xz": "cc58ce3af8f5481ada4dc129079cd558664717526b2f7f9a02bde6bafb6f45ad",
-    "dist/2024-04-29/rustc-nightly-loongarch64-unknown-linux-gnu.tar.gz": "34cfe803126ae9218b17adfe833a55c697dfa50729ac83b642529f3682d12d15",
-    "dist/2024-04-29/rustc-nightly-loongarch64-unknown-linux-gnu.tar.xz": "c752dc8962656c09047151fd24166f3134fbeed85006b5d22496691079c7fb9c",
-    "dist/2024-04-29/rustc-nightly-powerpc-unknown-linux-gnu.tar.gz": "386b086b8aad922050c813dd58bb79a52ef806b2d1413e2e9cc46d6e43b81d7c",
-    "dist/2024-04-29/rustc-nightly-powerpc-unknown-linux-gnu.tar.xz": "d9eec9ab7c265444ac5f04d4ec9e77d4c0c3c2e34c5804db8abf5f94c8fd2272",
-    "dist/2024-04-29/rustc-nightly-powerpc64-unknown-linux-gnu.tar.gz": "91df129046443554bfb836d25886aa9807b917acbc9dcf30f6531cde7bf912fa",
-    "dist/2024-04-29/rustc-nightly-powerpc64-unknown-linux-gnu.tar.xz": "ca9b574b9f2e914b5a6d9e011aba805d1e6f9b687dc1a1868e88f0e4d9e4401c",
-    "dist/2024-04-29/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "8b44f96a1ccd6d501b0af3960edb2c1a6c93957676a1c2cdb831e614de398f8b",
-    "dist/2024-04-29/rustc-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "f8a10a6767b80bf24f73223b9e46e1b18b6bf6746ad2115eb8968a0e482f0e4e",
-    "dist/2024-04-29/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "a197208807503a9cfbc6df938d614a192da48884b2e4892f7b1d234579091be1",
-    "dist/2024-04-29/rustc-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "af3a1a33942bd8a3417593dc118abb1db0373f5410f54771713c05bb86724fed",
-    "dist/2024-04-29/rustc-nightly-s390x-unknown-linux-gnu.tar.gz": "5a3a3aa73b6a0f21c63b9a40bdbd0bb4dc59bd75add0a06e292ced791fad31be",
-    "dist/2024-04-29/rustc-nightly-s390x-unknown-linux-gnu.tar.xz": "6d7903f1c9fc95a23448717326d667dce59e54aaff821443d3cd9137cf3537fb",
-    "dist/2024-04-29/rustc-nightly-x86_64-apple-darwin.tar.gz": "64eede54da4bf88b0a42ecf7f7a4bf8002b5550e60a64e1e48244c7f5b04768c",
-    "dist/2024-04-29/rustc-nightly-x86_64-apple-darwin.tar.xz": "0a8f95e3bb0bebf9bcc8116b91bab3ba97cb6ff4021713586280aaceed9da030",
-    "dist/2024-04-29/rustc-nightly-x86_64-pc-windows-gnu.tar.gz": "58f9e0dd9c1aadde2dfd869528adadd4acc29ab0850236f3cee5f023d4211939",
-    "dist/2024-04-29/rustc-nightly-x86_64-pc-windows-gnu.tar.xz": "a211a962093e0d09358d51a6eb48da0966a02383c6b00c8acc077b5663d7d707",
-    "dist/2024-04-29/rustc-nightly-x86_64-pc-windows-msvc.tar.gz": "5631926874dc54204c319137a77a89de5e6f408de2a832109e2be71ea79f27d1",
-    "dist/2024-04-29/rustc-nightly-x86_64-pc-windows-msvc.tar.xz": "a8cf87bc663b5e3dbcc97b0eb58bb1b9b5b0100aacb47dc0c372fe1612517244",
-    "dist/2024-04-29/rustc-nightly-x86_64-unknown-freebsd.tar.gz": "1011f98197a9fe82d6095f4521934a06eea5f7e9719a6e4c9e3bf13d68f799ca",
-    "dist/2024-04-29/rustc-nightly-x86_64-unknown-freebsd.tar.xz": "79599b3f91f9372262e97a417f4e104ef5192c0f6f8df204aea9c8b3ee39430e",
-    "dist/2024-04-29/rustc-nightly-x86_64-unknown-illumos.tar.gz": "7179a453bdcb17e401c0af8f4ab86cb5a4752a8ec80b0cbdd4cf1854c7f36a35",
-    "dist/2024-04-29/rustc-nightly-x86_64-unknown-illumos.tar.xz": "d565fc366fdbc305fbfe59e72b971c58f201d69e03a9ffa667d2ca0735cdb7f3",
-    "dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-gnu.tar.gz": "ae6bd8e20560d48519290d78e3d21f84b983403ca1f8f466a85496276d7866da",
-    "dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-gnu.tar.xz": "c7c0f8f44b0275456a27952178caa04c32eb9a1507056ddc05926a0730e17359",
-    "dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-musl.tar.gz": "3246797ddbc9118de819b13b005b83748338f3c825a7436ebd5aa79ca55539c0",
-    "dist/2024-04-29/rustc-nightly-x86_64-unknown-linux-musl.tar.xz": "c7e784e77dbabedad88d24d2ae6dc4abb68bc04b1cd6c9d45f6dc28b6d0e2edc",
-    "dist/2024-04-29/rustc-nightly-x86_64-unknown-netbsd.tar.gz": "c9452de4b3f15f0cf0b7d737b217b2cc7b88a96543bd8ce587ee14be1e21a90a",
-    "dist/2024-04-29/rustc-nightly-x86_64-unknown-netbsd.tar.xz": "de9b05278a5c69d53ccbb31223526ea2aa2275c0fb3f046d1c1b4d67c0b0c275",
-    "dist/2024-04-29/rustfmt-nightly-aarch64-apple-darwin.tar.gz": "3734353a58dbf6c3831cc6b4ea606357140c191c89e8dfca1d7aa2f3fb8ac53d",
-    "dist/2024-04-29/rustfmt-nightly-aarch64-apple-darwin.tar.xz": "e5e3a6e609fbfd537aa4acfefd3681d4b6c8029e2801a1ef23e8b09cf5a47bfe",
-    "dist/2024-04-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.gz": "22f54857e01d759301d099b67547cdc485596499088d0d749d38058c28e0f752",
-    "dist/2024-04-29/rustfmt-nightly-aarch64-pc-windows-msvc.tar.xz": "db48a9d45dc7c7aad4c9bb0d20789dd35fb6ef7a966948c44fbbae132de4c16b",
-    "dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.gz": "fa5d1fb9f3627e7d59269a1f8008d780c685ea04975473f1808287134e7bc5a7",
-    "dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-gnu.tar.xz": "61ab625b47fa9097af90a79a1e75a2f2492a415f4009c9043cf453bd4128f031",
-    "dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.gz": "cc79969341fc60991059d0e3f13a69489c1e0915ea5787a88b8605ed5b7f3cd0",
-    "dist/2024-04-29/rustfmt-nightly-aarch64-unknown-linux-musl.tar.xz": "bbdb75f922b4b1716b033d91c76c4c0aa53061d6e7fa53a9bf16fe076814bbb2",
-    "dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.gz": "13ca68afc3f3970a37951504664b58035102e1ae06d10a744389603b2f7499f5",
-    "dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabi.tar.xz": "04b174aa724945b6359a555892506c6a742a7c427464e8206433bb3f9a65fc02",
-    "dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.gz": "430333380a590a9de211c8d735989fedb89321cf9f5f9a0b1ef651ec8b598691",
-    "dist/2024-04-29/rustfmt-nightly-arm-unknown-linux-gnueabihf.tar.xz": "924713e648806945cd56e54d4c11dc74b65241c8dbf6cc7b401c5c93d0f7ffdb",
-    "dist/2024-04-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.gz": "bb6e5a8b5cc88099e613aa5f4d926165976d8e4a7fccbecf4ac3b0eb966d7a0f",
-    "dist/2024-04-29/rustfmt-nightly-armv7-unknown-linux-gnueabihf.tar.xz": "34d5e970304e1734aacb26c095e926c27a07e1a41fe70db9fa2997bef97ad3ec",
-    "dist/2024-04-29/rustfmt-nightly-i686-pc-windows-gnu.tar.gz": "835447a1d9d60659e99903275f327641809fc0148f35149f980d1a17ff87cc9a",
-    "dist/2024-04-29/rustfmt-nightly-i686-pc-windows-gnu.tar.xz": "ddd84a7f900aa239f93711f7da71e57aaedeeba2c9c8a8f23608acc7e48613c0",
-    "dist/2024-04-29/rustfmt-nightly-i686-pc-windows-msvc.tar.gz": "02f0af2bdae167c6091099a9b54ceb150c22b0f20dc861587a02cac78deb0b39",
-    "dist/2024-04-29/rustfmt-nightly-i686-pc-windows-msvc.tar.xz": "822f78f39dcbe3282bf7888a8cdae04efe7b023ded026a7e7f430e4ff15e7942",
-    "dist/2024-04-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.gz": "68a6189652c11a2c142c5339e2f5fb09d5f3e85d860bff063f62d5d3a3d111bf",
-    "dist/2024-04-29/rustfmt-nightly-i686-unknown-linux-gnu.tar.xz": "6740ea882effa2fb87dd72744c08888ce5ec59c9797c00369156b24847bb180e",
-    "dist/2024-04-29/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.gz": "0bb365e2d895ef3c39c4899a01187a23f9b7c5195c30bf845da3917f62f5eafd",
-    "dist/2024-04-29/rustfmt-nightly-loongarch64-unknown-linux-gnu.tar.xz": "2e54c9887bc6ed1eb09b9f69c8425da843ea12bf33248fa0ccdc0d14387c1c57",
-    "dist/2024-04-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.gz": "b0c0fe437921d17e2f50cbff87beeac067efa3d5211a241fb6f4c10b8ab500ac",
-    "dist/2024-04-29/rustfmt-nightly-powerpc-unknown-linux-gnu.tar.xz": "64e7282c0cf4a714b11eed1d28be3a64ba0ccc6d899211a872a5a7809d514c08",
-    "dist/2024-04-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.gz": "100cfde057c81460b8cfde2047fe83ddde360a6df1ff178da5a968b17ecc9df8",
-    "dist/2024-04-29/rustfmt-nightly-powerpc64-unknown-linux-gnu.tar.xz": "38e8712e98fa0bc6962ab2fd2e3b96a2a5dcaa6c16161d8caf71131a1ca5031e",
-    "dist/2024-04-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.gz": "4dab52b50e19348fb39fdad39ab44189c27c10f80b5fbe2cc4723b644611fa87",
-    "dist/2024-04-29/rustfmt-nightly-powerpc64le-unknown-linux-gnu.tar.xz": "36d1b2c9150fafc5976c296200ba3fac3e923df3e6f18032068200e2a887146c",
-    "dist/2024-04-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.gz": "7cb4a536320c23d305ce3bd3b7a954d951bf4d358ef3732be75b9b290c4818a5",
-    "dist/2024-04-29/rustfmt-nightly-riscv64gc-unknown-linux-gnu.tar.xz": "ede1afc7dc5892ef6f780e987737e145c4b4d00495da8c2e9902182a3a174e20",
-    "dist/2024-04-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.gz": "e2d2d561cbfa0add0e5349682976216d3a7cff4094372c1ed26854bb4e4d93fd",
-    "dist/2024-04-29/rustfmt-nightly-s390x-unknown-linux-gnu.tar.xz": "e0380e65e83e4131f6aa7ee4e185689add4372b0c1653312e2ffd56072fdd0fe",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-apple-darwin.tar.gz": "73a140c7ed9c80f209ff976c63b0a34d625d651553c38692c91f048f4e0ae470",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-apple-darwin.tar.xz": "9946b7120465181e05916b8023bc075b32bd85cf45a3b1d8bfba2f94ac78d927",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.gz": "eda273f27714b1e45adcc2388149f48de0e32a9104db0b9d1a02f6d37de43fef",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-gnu.tar.xz": "f2955a4b696d050c219a96c093162b42a2fab921f9f3cb7570f8462928306c6d",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.gz": "ec900cc2d3c6d45ef039653f4418f9b9a4a5fddd5d7e8077c3fb08b36c539a28",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-pc-windows-msvc.tar.xz": "04e6999a3405acc79f5fdcafeeab52880e5eeeedd3909b5f3c57e7647c86ef99",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.gz": "0730c5ebd576fec5371085f9fac0adde9424e1d7626456ed33bc66351b0ad307",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-freebsd.tar.xz": "90cbd84b8d48f0235a1954166f5edd53dc3031532ec6dfcb364f9a9624c9ce11",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-illumos.tar.gz": "5f5c62d321db27eb495f6ea312ef8bea0bf17a7a501a44e062986c416951700f",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-illumos.tar.xz": "a3bf64e2f22436e4484fc818f69d2f750fddd05a96463fd4abfcf655edce36b9",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.gz": "a847a6f9c7a3ce71c7cd8d81bdfcfcd8e4d128aa28ba0dafea89b0cc37c6c36c",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-gnu.tar.xz": "21fa794456566c64d08f629a385f89b3cfe9d9b69f317ae85fbe7425419108ff",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.gz": "b3f792f10a98993b4b55d1df951727a4422102d51b1145e51824268d48587ad0",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-linux-musl.tar.xz": "d791f0ec3c004e7baa0381962bf8ca2f18a3c861152702de5301d0149260e7fa",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.gz": "9807b2887e976d29f0c04484f8459175b4f6b70ef000037cdc4dada48e3cbd74",
-    "dist/2024-04-29/rustfmt-nightly-x86_64-unknown-netbsd.tar.xz": "019920d64778af62879e2146c2c13d9f6e2165a38bbfa1982694bfb48864d308"
-  }
-}
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index f397234..bed7626 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -236,7 +236,7 @@
     let num_threads = if let Some(num) = env::var_os("BUILD_MANIFEST_NUM_THREADS") {
         num.to_str().unwrap().parse().expect("invalid number for BUILD_MANIFEST_NUM_THREADS")
     } else {
-        std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get)
+        std::thread::available_parallelism().map_or(1, std::num::NonZero::get)
     };
     rayon::ThreadPoolBuilder::new()
         .num_threads(num_threads)
diff --git a/src/tools/build_helper/src/lib.rs b/src/tools/build_helper/src/lib.rs
index 575f367..6a4e86e 100644
--- a/src/tools/build_helper/src/lib.rs
+++ b/src/tools/build_helper/src/lib.rs
@@ -2,3 +2,4 @@
 pub mod git;
 pub mod metrics;
 pub mod util;
+pub mod stage0_parser;
diff --git a/src/tools/build_helper/src/stage0_parser.rs b/src/tools/build_helper/src/stage0_parser.rs
new file mode 100644
index 0000000..ff05b11
--- /dev/null
+++ b/src/tools/build_helper/src/stage0_parser.rs
@@ -0,0 +1,76 @@
+use std::collections::BTreeMap;
+
+#[derive(Default, Clone)]
+pub struct Stage0 {
+    pub compiler: VersionMetadata,
+    pub rustfmt: Option<VersionMetadata>,
+    pub config: Stage0Config,
+    pub checksums_sha256: BTreeMap<String, String>,
+}
+
+#[derive(Default, Clone)]
+pub struct VersionMetadata {
+    pub date: String,
+    pub version: String,
+}
+
+#[derive(Default, Clone)]
+pub struct Stage0Config {
+    pub dist_server: String,
+    pub artifacts_server: String,
+    pub artifacts_with_llvm_assertions_server: String,
+    pub git_merge_commit_email: String,
+    pub git_repository: String,
+    pub nightly_branch: String,
+}
+
+pub fn parse_stage0_file() -> Stage0 {
+    let stage0_content = include_str!("../../../stage0");
+
+    let mut stage0 = Stage0::default();
+    for line in stage0_content.lines() {
+        let line = line.trim();
+
+        if line.is_empty() {
+            continue;
+        }
+
+        // Ignore comments
+        if line.starts_with('#') {
+            continue;
+        }
+
+        let (key, value) = line.split_once('=').unwrap();
+
+        match key {
+            "dist_server" => stage0.config.dist_server = value.to_owned(),
+            "artifacts_server" => stage0.config.artifacts_server = value.to_owned(),
+            "artifacts_with_llvm_assertions_server" => {
+                stage0.config.artifacts_with_llvm_assertions_server = value.to_owned()
+            }
+            "git_merge_commit_email" => stage0.config.git_merge_commit_email = value.to_owned(),
+            "git_repository" => stage0.config.git_repository = value.to_owned(),
+            "nightly_branch" => stage0.config.nightly_branch = value.to_owned(),
+
+            "compiler_date" => stage0.compiler.date = value.to_owned(),
+            "compiler_version" => stage0.compiler.version = value.to_owned(),
+
+            "rustfmt_date" => {
+                stage0.rustfmt.get_or_insert(VersionMetadata::default()).date = value.to_owned();
+            }
+            "rustfmt_version" => {
+                stage0.rustfmt.get_or_insert(VersionMetadata::default()).version = value.to_owned();
+            }
+
+            dist if dist.starts_with("dist") => {
+                stage0.checksums_sha256.insert(key.to_owned(), value.to_owned());
+            }
+
+            unsupported => {
+                println!("'{unsupported}' field is not supported.");
+            }
+        }
+    }
+
+    stage0
+}
diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml
index 4680a7a..de5d821 100644
--- a/src/tools/bump-stage0/Cargo.toml
+++ b/src/tools/bump-stage0/Cargo.toml
@@ -7,8 +7,8 @@
 
 [dependencies]
 anyhow = "1.0.34"
+build_helper = { path = "../build_helper" }
 curl = "0.4.38"
 indexmap = { version = "2.0.0", features = ["serde"] }
 serde = { version = "1.0.125", features = ["derive"] }
-serde_json = { version = "1.0.59", features = ["preserve_order"] }
 toml = "0.5.7"
diff --git a/src/tools/bump-stage0/src/main.rs b/src/tools/bump-stage0/src/main.rs
index bd97b4e..bb06e11 100644
--- a/src/tools/bump-stage0/src/main.rs
+++ b/src/tools/bump-stage0/src/main.rs
@@ -1,15 +1,17 @@
+#![deny(unused_variables)]
+
 use anyhow::{Context, Error};
+use build_helper::stage0_parser::{parse_stage0_file, Stage0Config, VersionMetadata};
 use curl::easy::Easy;
 use indexmap::IndexMap;
 use std::collections::HashMap;
 
-const PATH: &str = "src/stage0.json";
+const PATH: &str = "src/stage0";
 const COMPILER_COMPONENTS: &[&str] = &["rustc", "rust-std", "cargo", "clippy-preview"];
 const RUSTFMT_COMPONENTS: &[&str] = &["rustfmt-preview", "rustc"];
 
 struct Tool {
-    config: Config,
-    comments: Vec<String>,
+    config: Stage0Config,
 
     channel: Channel,
     date: Option<String>,
@@ -35,37 +37,64 @@
             .try_into()
             .map_err(|_| anyhow::anyhow!("failed to parse version"))?;
 
-        let existing: Stage0 = serde_json::from_slice(&std::fs::read(PATH)?)?;
+        let existing = parse_stage0_file();
 
-        Ok(Self {
-            channel,
-            version,
-            date,
-            config: existing.config,
-            comments: existing.comments,
-            checksums: IndexMap::new(),
-        })
+        Ok(Self { channel, version, date, config: existing.config, checksums: IndexMap::new() })
     }
 
-    fn update_json(mut self) -> Result<(), Error> {
-        std::fs::write(
-            PATH,
-            format!(
-                "{}\n",
-                serde_json::to_string_pretty(&Stage0 {
-                    compiler: self.detect_compiler()?,
-                    rustfmt: self.detect_rustfmt()?,
-                    checksums_sha256: {
-                        // Keys are sorted here instead of beforehand because values in this map
-                        // are added while filling the other struct fields just above this block.
-                        self.checksums.sort_keys();
-                        self.checksums
-                    },
-                    config: self.config,
-                    comments: self.comments,
-                })?
-            ),
-        )?;
+    fn update_stage0_file(mut self) -> Result<(), Error> {
+        const COMMENTS: &str = r#"# The configuration above this comment is editable, and can be changed
+# by forks of the repository if they have alternate values.
+#
+# The section below is generated by `./x.py run src/tools/bump-stage0`,
+# run that command again to update the bootstrap compiler.
+#
+# All changes below this comment will be overridden the next time the
+# tool is executed.
+            "#;
+
+        let mut file_content = String::new();
+
+        // Destructure `Stage0Config` here to ensure the stage0 file is synced with any new
+        // fields when they are added.
+        let Stage0Config {
+            dist_server,
+            artifacts_server,
+            artifacts_with_llvm_assertions_server,
+            git_merge_commit_email,
+            git_repository,
+            nightly_branch,
+        } = &self.config;
+
+        file_content.push_str(&format!("dist_server={}", dist_server));
+        file_content.push_str(&format!("\nartifacts_server={}", artifacts_server));
+        file_content.push_str(&format!(
+            "\nartifacts_with_llvm_assertions_server={}",
+            artifacts_with_llvm_assertions_server
+        ));
+        file_content.push_str(&format!("\ngit_merge_commit_email={}", git_merge_commit_email));
+        file_content.push_str(&format!("\ngit_repository={}", git_repository));
+        file_content.push_str(&format!("\nnightly_branch={}", nightly_branch));
+
+        file_content.push_str("\n\n");
+        file_content.push_str(COMMENTS);
+
+        let compiler = self.detect_compiler()?;
+        file_content.push_str(&format!("\ncompiler_date={}", compiler.date));
+        file_content.push_str(&format!("\ncompiler_version={}", compiler.version));
+
+        if let Some(rustfmt) = self.detect_rustfmt()? {
+            file_content.push_str(&format!("\nrustfmt_date={}", rustfmt.date));
+            file_content.push_str(&format!("\nrustfmt_version={}", rustfmt.version));
+        }
+
+        file_content.push_str("\n");
+
+        for (key, value) in self.checksums {
+            file_content.push_str(&format!("\n{}={}", key, value));
+        }
+
+        std::fs::write(PATH, file_content)?;
         Ok(())
     }
 
@@ -76,7 +105,7 @@
     // On the master branch the compiler version is configured to `beta` whereas if you're looking
     // at the beta or stable channel you'll likely see `1.x.0` as the version, with the previous
     // release's version number.
-    fn detect_compiler(&mut self) -> Result<Stage0Toolchain, Error> {
+    fn detect_compiler(&mut self) -> Result<VersionMetadata, Error> {
         let channel = match self.channel {
             Channel::Stable | Channel::Beta => {
                 // The 1.XX manifest points to the latest point release of that minor release.
@@ -87,7 +116,7 @@
 
         let manifest = fetch_manifest(&self.config, &channel, self.date.as_deref())?;
         self.collect_checksums(&manifest, COMPILER_COMPONENTS)?;
-        Ok(Stage0Toolchain {
+        Ok(VersionMetadata {
             date: manifest.date,
             version: if self.channel == Channel::Nightly {
                 "beta".to_string()
@@ -106,14 +135,14 @@
     /// We use a nightly rustfmt to format the source because it solves some bootstrapping issues
     /// with use of new syntax in this repo. For the beta/stable channels rustfmt is not provided,
     /// as we don't want to depend on rustfmt from nightly there.
-    fn detect_rustfmt(&mut self) -> Result<Option<Stage0Toolchain>, Error> {
+    fn detect_rustfmt(&mut self) -> Result<Option<VersionMetadata>, Error> {
         if self.channel != Channel::Nightly {
             return Ok(None);
         }
 
         let manifest = fetch_manifest(&self.config, "nightly", self.date.as_deref())?;
         self.collect_checksums(&manifest, RUSTFMT_COMPONENTS)?;
-        Ok(Some(Stage0Toolchain { date: manifest.date, version: "nightly".into() }))
+        Ok(Some(VersionMetadata { date: manifest.date, version: "nightly".into() }))
     }
 
     fn collect_checksums(&mut self, manifest: &Manifest, components: &[&str]) -> Result<(), Error> {
@@ -143,11 +172,15 @@
 
 fn main() -> Result<(), Error> {
     let tool = Tool::new(std::env::args().nth(1))?;
-    tool.update_json()?;
+    tool.update_stage0_file()?;
     Ok(())
 }
 
-fn fetch_manifest(config: &Config, channel: &str, date: Option<&str>) -> Result<Manifest, Error> {
+fn fetch_manifest(
+    config: &Stage0Config,
+    channel: &str,
+    date: Option<&str>,
+) -> Result<Manifest, Error> {
     let url = if let Some(date) = date {
         format!("{}/dist/{}/channel-rust-{}.toml", config.dist_server, date, channel)
     } else {
@@ -181,42 +214,6 @@
 }
 
 #[derive(Debug, serde::Serialize, serde::Deserialize)]
-struct Stage0 {
-    config: Config,
-    // Comments are explicitly below the config, do not move them above.
-    //
-    // Downstream forks of the compiler codebase can change the configuration values defined above,
-    // but doing so would risk merge conflicts whenever they import new changes that include a
-    // bootstrap compiler bump.
-    //
-    // To lessen the pain, a big block of comments is placed between the configuration and the
-    // auto-generated parts of the file, preventing git diffs of the config to include parts of the
-    // auto-generated content and vice versa. This should prevent merge conflicts.
-    #[serde(rename = "__comments")]
-    comments: Vec<String>,
-    compiler: Stage0Toolchain,
-    rustfmt: Option<Stage0Toolchain>,
-    checksums_sha256: IndexMap<String, String>,
-}
-
-#[derive(Debug, serde::Serialize, serde::Deserialize)]
-struct Config {
-    dist_server: String,
-    // There are other fields in the configuration, which will be read by src/bootstrap or other
-    // tools consuming stage0.json. To avoid the need to update bump-stage0 every time a new field
-    // is added, we collect all the fields in an untyped Value and serialize them back with the
-    // same order and structure they were deserialized in.
-    #[serde(flatten)]
-    other: serde_json::Value,
-}
-
-#[derive(Debug, serde::Serialize, serde::Deserialize)]
-struct Stage0Toolchain {
-    date: String,
-    version: String,
-}
-
-#[derive(Debug, serde::Serialize, serde::Deserialize)]
 struct Manifest {
     date: String,
     pkg: HashMap<String, ManifestPackage>,
diff --git a/src/tools/cargo b/src/tools/cargo
index 0ca60e9..84dc5dc 160000
--- a/src/tools/cargo
+++ b/src/tools/cargo
@@ -1 +1 @@
-Subproject commit 0ca60e940821c311c9b25a6423b59ccdbcea218f
+Subproject commit 84dc5dc11a9007a08f27170454da6097265e510e
diff --git a/src/tools/clippy/.github/driver.sh b/src/tools/clippy/.github/driver.sh
index 2eafdd0..09202b1 100755
--- a/src/tools/clippy/.github/driver.sh
+++ b/src/tools/clippy/.github/driver.sh
@@ -2,15 +2,18 @@
 
 set -ex
 
-# Check sysroot handling
-sysroot=$(./target/debug/clippy-driver --print sysroot)
-test "$sysroot" = "$(rustc --print sysroot)"
+sysroot="$(rustc --print sysroot)"
+case $OS in
+    Linux) export LD_LIBRARY_PATH="$sysroot/lib" ;;
+    macOS) export DYLD_FALLBACK_LIBRARY_PATH="$sysroot/lib" ;;
+    Windows) export PATH="$(cygpath "$sysroot")/bin:$PATH" ;;
+    *) exit 1
+esac
 
-if [[ ${OS} == "Windows" ]]; then
-	desired_sysroot=C:/tmp
-else
-	desired_sysroot=/tmp
-fi
+# Check sysroot handling
+test "$(./target/debug/clippy-driver --print sysroot)" = "$sysroot"
+
+desired_sysroot="target/sysroot"
 # Set --sysroot in command line
 sysroot=$(./target/debug/clippy-driver --sysroot $desired_sysroot --print sysroot)
 test "$sysroot" = $desired_sysroot
diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml
index 8179e3e..06bf3b6 100644
--- a/src/tools/clippy/.github/workflows/clippy.yml
+++ b/src/tools/clippy/.github/workflows/clippy.yml
@@ -69,6 +69,6 @@
       working-directory: clippy_dev
 
     - name: Test clippy-driver
-      run: |
-        TOOLCHAIN=$(rustup show active-toolchain | cut -f1 -d' ')
-        rustup run $TOOLCHAIN bash .github/driver.sh
+      run: .github/driver.sh
+      env:
+        OS: ${{ runner.os }}
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 9451598..1f4bec9 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -116,9 +116,7 @@
       working-directory: clippy_dev
 
     - name: Test clippy-driver
-      run: |
-        TOOLCHAIN=$(rustup show active-toolchain | cut -f1 -d' ')
-        rustup run $TOOLCHAIN bash .github/driver.sh
+      run: .github/driver.sh
       env:
         OS: ${{ runner.os }}
 
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 9c9ea11..d5115f7 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -5249,6 +5249,7 @@
 [`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type
 [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types
 [`diverging_sub_expression`]: https://rust-lang.github.io/rust-clippy/master/index.html#diverging_sub_expression
+[`doc_lazy_continuation`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_lazy_continuation
 [`doc_link_with_quotes`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_link_with_quotes
 [`doc_markdown`]: https://rust-lang.github.io/rust-clippy/master/index.html#doc_markdown
 [`double_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#double_comparisons
@@ -5447,6 +5448,7 @@
 [`little_endian_bytes`]: https://rust-lang.github.io/rust-clippy/master/index.html#little_endian_bytes
 [`logic_bug`]: https://rust-lang.github.io/rust-clippy/master/index.html#logic_bug
 [`lossy_float_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#lossy_float_literal
+[`macro_metavars_in_unsafe`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_metavars_in_unsafe
 [`macro_use_imports`]: https://rust-lang.github.io/rust-clippy/master/index.html#macro_use_imports
 [`main_recursion`]: https://rust-lang.github.io/rust-clippy/master/index.html#main_recursion
 [`manual_assert`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_assert
@@ -5702,6 +5704,7 @@
 [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref
 [`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns
 [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro
+[`renamed_function_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#renamed_function_params
 [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once
 [`repeat_vec_with_capacity`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_vec_with_capacity
 [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts
@@ -5908,6 +5911,7 @@
 [`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
 [`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons
 [`waker_clone_wake`]: https://rust-lang.github.io/rust-clippy/master/index.html#waker_clone_wake
+[`while_float`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_float
 [`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition
 [`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop
 [`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
@@ -5939,8 +5943,10 @@
 [`allow-expect-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-expect-in-tests
 [`allow-mixed-uninlined-format-args`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-mixed-uninlined-format-args
 [`allow-one-hash-in-raw-strings`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-one-hash-in-raw-strings
+[`allow-panic-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-panic-in-tests
 [`allow-print-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-print-in-tests
 [`allow-private-module-inception`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-private-module-inception
+[`allow-renamed-params-for`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-renamed-params-for
 [`allow-unwrap-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-unwrap-in-tests
 [`allow-useless-vec-in-tests`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allow-useless-vec-in-tests
 [`allowed-dotfiles`]: https://doc.rust-lang.org/clippy/lint_configuration.html#allowed-dotfiles
@@ -6002,4 +6008,5 @@
 [`vec-box-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#vec-box-size-threshold
 [`verbose-bit-mask-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#verbose-bit-mask-threshold
 [`warn-on-all-wildcard-imports`]: https://doc.rust-lang.org/clippy/lint_configuration.html#warn-on-all-wildcard-imports
+[`warn-unsafe-macro-metavars-in-private-macros`]: https://doc.rust-lang.org/clippy/lint_configuration.html#warn-unsafe-macro-metavars-in-private-macros
 <!-- end autogenerated links to configuration documentation -->
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index f6af981..c822300 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -101,6 +101,16 @@
 * [`unnecessary_raw_string_hashes`](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_raw_string_hashes)
 
 
+## `allow-panic-in-tests`
+Whether `panic` should be allowed in test functions or `#[cfg(test)]`
+
+**Default Value:** `false`
+
+---
+**Affected lints:**
+* [`panic`](https://rust-lang.github.io/rust-clippy/master/index.html#panic)
+
+
 ## `allow-print-in-tests`
 Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
 
@@ -122,6 +132,28 @@
 * [`module_inception`](https://rust-lang.github.io/rust-clippy/master/index.html#module_inception)
 
 
+## `allow-renamed-params-for`
+List of trait paths to ignore when checking renamed function parameters.
+
+#### Example
+
+```toml
+allow-renamed-params-for = [ "std::convert::From" ]
+```
+
+#### Noteworthy
+
+- By default, the following traits are ignored: `From`, `TryFrom`, `FromStr`
+- `".."` can be used as part of the list to indicate that the configured values should be appended to the
+default configuration of Clippy. By default, any configuration will replace the default value.
+
+**Default Value:** `["core::convert::From", "core::convert::TryFrom", "core::str::FromStr"]`
+
+---
+**Affected lints:**
+* [`renamed_function_params`](https://rust-lang.github.io/rust-clippy/master/index.html#renamed_function_params)
+
+
 ## `allow-unwrap-in-tests`
 Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
 
@@ -900,3 +932,13 @@
 * [`wildcard_imports`](https://rust-lang.github.io/rust-clippy/master/index.html#wildcard_imports)
 
 
+## `warn-unsafe-macro-metavars-in-private-macros`
+Whether to also emit warnings for unsafe blocks with metavariable expansions in **private** macros.
+
+**Default Value:** `false`
+
+---
+**Affected lints:**
+* [`macro_metavars_in_unsafe`](https://rust-lang.github.io/rust-clippy/master/index.html#macro_metavars_in_unsafe)
+
+
diff --git a/src/tools/clippy/clippy_config/src/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 5cfcbdb..cfdf620 100644
--- a/src/tools/clippy/clippy_config/src/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -40,6 +40,8 @@
 const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"];
 const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"];
 const DEFAULT_ALLOWED_PREFIXES: &[&str] = &["to", "as", "into", "from", "try_into", "try_from"];
+const DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS: &[&str] =
+    &["core::convert::From", "core::convert::TryFrom", "core::str::FromStr"];
 
 /// Conf with parse errors
 #[derive(Default)]
@@ -455,6 +457,10 @@
     ///
     /// Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
     (allow_unwrap_in_tests: bool = false),
+    /// Lint: PANIC.
+    ///
+    /// Whether `panic` should be allowed in test functions or `#[cfg(test)]`
+    (allow_panic_in_tests: bool = false),
     /// Lint: DBG_MACRO.
     ///
     /// Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
@@ -613,6 +619,27 @@
     /// - Use `".."` as part of the list to indicate that the configured values should be appended to the
     /// default configuration of Clippy. By default, any configuration will replace the default value
     (allowed_prefixes: Vec<String> = DEFAULT_ALLOWED_PREFIXES.iter().map(ToString::to_string).collect()),
+    /// Lint: RENAMED_FUNCTION_PARAMS.
+    ///
+    /// List of trait paths to ignore when checking renamed function parameters.
+    ///
+    /// #### Example
+    ///
+    /// ```toml
+    /// allow-renamed-params-for = [ "std::convert::From" ]
+    /// ```
+    ///
+    /// #### Noteworthy
+    ///
+    /// - By default, the following traits are ignored: `From`, `TryFrom`, `FromStr`
+    /// - `".."` can be used as part of the list to indicate that the configured values should be appended to the
+    /// default configuration of Clippy. By default, any configuration will replace the default value.
+    (allow_renamed_params_for: Vec<String> =
+        DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS.iter().map(ToString::to_string).collect()),
+    /// Lint: MACRO_METAVARS_IN_UNSAFE.
+    ///
+    /// Whether to also emit warnings for unsafe blocks with metavariable expansions in **private** macros.
+    (warn_unsafe_macro_metavars_in_private_macros: bool = false),
 }
 
 /// Search for the configuration file.
@@ -674,6 +701,10 @@
             extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
             extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
             extend_vec_if_indicator_present(&mut conf.conf.allowed_prefixes, DEFAULT_ALLOWED_PREFIXES);
+            extend_vec_if_indicator_present(
+                &mut conf.conf.allow_renamed_params_for,
+                DEFAULT_ALLOWED_TRAITS_WITH_RENAMED_PARAMS,
+            );
             // TODO: THIS SHOULD BE TESTED, this comment will be gone soon
             if conf.conf.allowed_idents_below_min_chars.contains("..") {
                 conf.conf
diff --git a/src/tools/clippy/clippy_config/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs
index 1480844..a3e7d0c 100644
--- a/src/tools/clippy/clippy_config/src/msrvs.rs
+++ b/src/tools/clippy/clippy_config/src/msrvs.rs
@@ -26,7 +26,8 @@
     1,63,0 { CLONE_INTO }
     1,62,0 { BOOL_THEN_SOME, DEFAULT_ENUM_ATTRIBUTE }
     1,59,0 { THREAD_LOCAL_INITIALIZER_CAN_BE_MADE_CONST }
-    1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY }
+    1,58,0 { FORMAT_ARGS_CAPTURE, PATTERN_TRAIT_CHAR_ARRAY, CONST_RAW_PTR_DEREF }
+    1,56,0 { CONST_FN_UNION }
     1,55,0 { SEEK_REWIND }
     1,54,0 { INTO_KEYS }
     1,53,0 { OR_PATTERNS, MANUAL_BITS, BTREE_MAP_RETAIN, BTREE_SET_RETAIN, ARRAY_INTO_ITERATOR }
diff --git a/src/tools/clippy/clippy_dev/Cargo.toml b/src/tools/clippy/clippy_dev/Cargo.toml
index 42a9530..4104e7d 100644
--- a/src/tools/clippy/clippy_dev/Cargo.toml
+++ b/src/tools/clippy/clippy_dev/Cargo.toml
@@ -1,11 +1,12 @@
 [package]
 name = "clippy_dev"
+description = "Clippy developer tooling"
 version = "0.0.1"
 edition = "2021"
 
 [dependencies]
 aho-corasick = "1.0"
-clap = "4.1.4"
+clap = { version = "4.4", features = ["derive"] }
 indoc = "1.0"
 itertools = "0.12"
 opener = "0.6"
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index 397a0e9..366b52b 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -2,350 +2,292 @@
 // warn on lints, that are included in `rust-lang/rust`s bootstrap
 #![warn(rust_2018_idioms, unused_lifetimes)]
 
-use clap::{Arg, ArgAction, ArgMatches, Command};
+use clap::{Args, Parser, Subcommand};
 use clippy_dev::{dogfood, fmt, lint, new_lint, serve, setup, update_lints};
-use indoc::indoc;
 use std::convert::Infallible;
 
 fn main() {
-    let matches = get_clap_config();
+    let dev = Dev::parse();
 
-    match matches.subcommand() {
-        Some(("bless", _)) => {
+    match dev.command {
+        DevCommand::Bless => {
             eprintln!("use `cargo bless` to automatically replace `.stderr` and `.fixed` files as tests are being run");
         },
-        Some(("dogfood", matches)) => {
-            dogfood::dogfood(
-                matches.get_flag("fix"),
-                matches.get_flag("allow-dirty"),
-                matches.get_flag("allow-staged"),
-            );
-        },
-        Some(("fmt", matches)) => {
-            fmt::run(matches.get_flag("check"), matches.get_flag("verbose"));
-        },
-        Some(("update_lints", matches)) => {
-            if matches.get_flag("print-only") {
+        DevCommand::Dogfood {
+            fix,
+            allow_dirty,
+            allow_staged,
+        } => dogfood::dogfood(fix, allow_dirty, allow_staged),
+        DevCommand::Fmt { check, verbose } => fmt::run(check, verbose),
+        DevCommand::UpdateLints { print_only, check } => {
+            if print_only {
                 update_lints::print_lints();
-            } else if matches.get_flag("check") {
+            } else if check {
                 update_lints::update(update_lints::UpdateMode::Check);
             } else {
                 update_lints::update(update_lints::UpdateMode::Change);
             }
         },
-        Some(("new_lint", matches)) => {
-            match new_lint::create(
-                matches.get_one::<String>("pass").unwrap(),
-                matches.get_one::<String>("name"),
-                matches.get_one::<String>("category").map(String::as_str),
-                matches.get_one::<String>("type").map(String::as_str),
-                matches.get_flag("msrv"),
-            ) {
-                Ok(()) => update_lints::update(update_lints::UpdateMode::Change),
-                Err(e) => eprintln!("Unable to create lint: {e}"),
-            }
+        DevCommand::NewLint {
+            pass,
+            name,
+            category,
+            r#type,
+            msrv,
+        } => match new_lint::create(&pass, &name, &category, r#type.as_deref(), msrv) {
+            Ok(()) => update_lints::update(update_lints::UpdateMode::Change),
+            Err(e) => eprintln!("Unable to create lint: {e}"),
         },
-        Some(("setup", sub_command)) => match sub_command.subcommand() {
-            Some(("git-hook", matches)) => {
-                if matches.get_flag("remove") {
-                    setup::git_hook::remove_hook();
-                } else {
-                    setup::git_hook::install_hook(matches.get_flag("force-override"));
-                }
-            },
-            Some(("intellij", matches)) => {
-                if matches.get_flag("remove") {
+        DevCommand::Setup(SetupCommand { subcommand }) => match subcommand {
+            SetupSubcommand::Intellij { remove, repo_path } => {
+                if remove {
                     setup::intellij::remove_rustc_src();
                 } else {
-                    setup::intellij::setup_rustc_src(
-                        matches
-                            .get_one::<String>("rustc-repo-path")
-                            .expect("this field is mandatory and therefore always valid"),
-                    );
+                    setup::intellij::setup_rustc_src(&repo_path);
                 }
             },
-            Some(("toolchain", matches)) => {
-                setup::toolchain::create(
-                    matches.get_flag("force"),
-                    matches.get_flag("release"),
-                    matches.get_one::<String>("name").unwrap(),
-                );
+            SetupSubcommand::GitHook { remove, force_override } => {
+                if remove {
+                    setup::git_hook::remove_hook();
+                } else {
+                    setup::git_hook::install_hook(force_override);
+                }
             },
-            Some(("vscode-tasks", matches)) => {
-                if matches.get_flag("remove") {
+            SetupSubcommand::Toolchain { force, release, name } => setup::toolchain::create(force, release, &name),
+            SetupSubcommand::VscodeTasks { remove, force_override } => {
+                if remove {
                     setup::vscode::remove_tasks();
                 } else {
-                    setup::vscode::install_tasks(matches.get_flag("force-override"));
+                    setup::vscode::install_tasks(force_override);
                 }
             },
-            _ => {},
         },
-        Some(("remove", sub_command)) => match sub_command.subcommand() {
-            Some(("git-hook", _)) => setup::git_hook::remove_hook(),
-            Some(("intellij", _)) => setup::intellij::remove_rustc_src(),
-            Some(("vscode-tasks", _)) => setup::vscode::remove_tasks(),
-            _ => {},
+        DevCommand::Remove(RemoveCommand { subcommand }) => match subcommand {
+            RemoveSubcommand::Intellij => setup::intellij::remove_rustc_src(),
+            RemoveSubcommand::GitHook => setup::git_hook::remove_hook(),
+            RemoveSubcommand::VscodeTasks => setup::vscode::remove_tasks(),
         },
-        Some(("serve", matches)) => {
-            let port = *matches.get_one::<u16>("port").unwrap();
-            let lint = matches.get_one::<String>("lint");
-            serve::run(port, lint);
-        },
-        Some(("lint", matches)) => {
-            let path = matches.get_one::<String>("path").unwrap();
-            let args = matches.get_many::<String>("args").into_iter().flatten();
-            lint::run(path, args);
-        },
-        Some(("rename_lint", matches)) => {
-            let old_name = matches.get_one::<String>("old_name").unwrap();
-            let new_name = matches.get_one::<String>("new_name").unwrap_or(old_name);
-            let uplift = matches.get_flag("uplift");
-            update_lints::rename(old_name, new_name, uplift);
-        },
-        Some(("deprecate", matches)) => {
-            let name = matches.get_one::<String>("name").unwrap();
-            let reason = matches.get_one("reason");
-            update_lints::deprecate(name, reason);
-        },
-        _ => {},
+        DevCommand::Serve { port, lint } => serve::run(port, lint),
+        DevCommand::Lint { path, args } => lint::run(&path, args.iter()),
+        DevCommand::RenameLint {
+            old_name,
+            new_name,
+            uplift,
+        } => update_lints::rename(&old_name, new_name.as_ref().unwrap_or(&old_name), uplift),
+        DevCommand::Deprecate { name, reason } => update_lints::deprecate(&name, reason.as_deref()),
     }
 }
 
-fn get_clap_config() -> ArgMatches {
-    Command::new("Clippy developer tooling")
-        .arg_required_else_help(true)
-        .subcommands([
-            Command::new("bless").about("bless the test output changes").arg(
-                Arg::new("ignore-timestamp")
-                    .long("ignore-timestamp")
-                    .action(ArgAction::SetTrue)
-                    .help("Include files updated before clippy was built"),
-            ),
-            Command::new("dogfood").about("Runs the dogfood test").args([
-                Arg::new("fix")
-                    .long("fix")
-                    .action(ArgAction::SetTrue)
-                    .help("Apply the suggestions when possible"),
-                Arg::new("allow-dirty")
-                    .long("allow-dirty")
-                    .action(ArgAction::SetTrue)
-                    .help("Fix code even if the working directory has changes")
-                    .requires("fix"),
-                Arg::new("allow-staged")
-                    .long("allow-staged")
-                    .action(ArgAction::SetTrue)
-                    .help("Fix code even if the working directory has staged changes")
-                    .requires("fix"),
-            ]),
-            Command::new("fmt")
-                .about("Run rustfmt on all projects and tests")
-                .args([
-                    Arg::new("check")
-                        .long("check")
-                        .action(ArgAction::SetTrue)
-                        .help("Use the rustfmt --check option"),
-                    Arg::new("verbose")
-                        .short('v')
-                        .long("verbose")
-                        .action(ArgAction::SetTrue)
-                        .help("Echo commands run"),
-                ]),
-            Command::new("update_lints")
-                .about("Updates lint registration and information from the source code")
-                .long_about(
-                    "Makes sure that:\n \
-                    * the lint count in README.md is correct\n \
-                    * the changelog contains markdown link references at the bottom\n \
-                    * all lint groups include the correct lints\n \
-                    * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod`\n \
-                    * all lints are registered in the lint store",
-                )
-                .args([
-                    Arg::new("print-only")
-                        .long("print-only")
-                        .action(ArgAction::SetTrue)
-                        .help(
-                            "Print a table of lints to STDOUT. \
-                            This does not include deprecated and internal lints. \
-                            (Does not modify any files)",
-                        ),
-                    Arg::new("check")
-                        .long("check")
-                        .action(ArgAction::SetTrue)
-                        .help("Checks that `cargo dev update_lints` has been run. Used on CI."),
-                ]),
-            Command::new("new_lint")
-                .about("Create new lint and run `cargo dev update_lints`")
-                .args([
-                    Arg::new("pass")
-                        .short('p')
-                        .long("pass")
-                        .help("Specify whether the lint runs during the early or late pass")
-                        .value_parser(["early", "late"])
-                        .conflicts_with("type")
-                        .default_value("late"),
-                    Arg::new("name")
-                        .short('n')
-                        .long("name")
-                        .help("Name of the new lint in snake case, ex: fn_too_long")
-                        .required(true)
-                        .value_parser(|name: &str| Ok::<_, Infallible>(name.replace('-', "_"))),
-                    Arg::new("category")
-                        .short('c')
-                        .long("category")
-                        .help("What category the lint belongs to")
-                        .default_value("nursery")
-                        .value_parser([
-                            "style",
-                            "correctness",
-                            "suspicious",
-                            "complexity",
-                            "perf",
-                            "pedantic",
-                            "restriction",
-                            "cargo",
-                            "nursery",
-                            "internal",
-                        ]),
-                    Arg::new("type").long("type").help("What directory the lint belongs in"),
-                    Arg::new("msrv")
-                        .long("msrv")
-                        .action(ArgAction::SetTrue)
-                        .help("Add MSRV config code to the lint"),
-                ]),
-            Command::new("setup")
-                .about("Support for setting up your personal development environment")
-                .arg_required_else_help(true)
-                .subcommands([
-                    Command::new("git-hook")
-                        .about("Add a pre-commit git hook that formats your code to make it look pretty")
-                        .args([
-                            Arg::new("remove")
-                                .long("remove")
-                                .action(ArgAction::SetTrue)
-                                .help("Remove the pre-commit hook added with 'cargo dev setup git-hook'"),
-                            Arg::new("force-override")
-                                .long("force-override")
-                                .short('f')
-                                .action(ArgAction::SetTrue)
-                                .help("Forces the override of an existing git pre-commit hook"),
-                        ]),
-                    Command::new("intellij")
-                        .about("Alter dependencies so Intellij Rust can find rustc internals")
-                        .args([
-                            Arg::new("remove")
-                                .long("remove")
-                                .action(ArgAction::SetTrue)
-                                .help("Remove the dependencies added with 'cargo dev setup intellij'"),
-                            Arg::new("rustc-repo-path")
-                                .long("repo-path")
-                                .short('r')
-                                .help("The path to a rustc repo that will be used for setting the dependencies")
-                                .value_name("path")
-                                .conflicts_with("remove")
-                                .required(true),
-                        ]),
-                    Command::new("toolchain")
-                        .about("Install a rustup toolchain pointing to the local clippy build")
-                        .args([
-                            Arg::new("force")
-                                .long("force")
-                                .short('f')
-                                .action(ArgAction::SetTrue)
-                                .help("Override an existing toolchain"),
-                            Arg::new("release")
-                                .long("release")
-                                .short('r')
-                                .action(ArgAction::SetTrue)
-                                .help("Point to --release clippy binaries"),
-                            Arg::new("name")
-                                .long("name")
-                                .default_value("clippy")
-                                .help("The name of the created toolchain"),
-                        ]),
-                    Command::new("vscode-tasks")
-                        .about("Add several tasks to vscode for formatting, validation and testing")
-                        .args([
-                            Arg::new("remove")
-                                .long("remove")
-                                .action(ArgAction::SetTrue)
-                                .help("Remove the tasks added with 'cargo dev setup vscode-tasks'"),
-                            Arg::new("force-override")
-                                .long("force-override")
-                                .short('f')
-                                .action(ArgAction::SetTrue)
-                                .help("Forces the override of existing vscode tasks"),
-                        ]),
-                ]),
-            Command::new("remove")
-                .about("Support for undoing changes done by the setup command")
-                .arg_required_else_help(true)
-                .subcommands([
-                    Command::new("git-hook").about("Remove any existing pre-commit git hook"),
-                    Command::new("vscode-tasks").about("Remove any existing vscode tasks"),
-                    Command::new("intellij").about("Removes rustc source paths added via `cargo dev setup intellij`"),
-                ]),
-            Command::new("serve")
-                .about("Launch a local 'ALL the Clippy Lints' website in a browser")
-                .args([
-                    Arg::new("port")
-                        .long("port")
-                        .short('p')
-                        .help("Local port for the http server")
-                        .default_value("8000")
-                        .value_parser(clap::value_parser!(u16)),
-                    Arg::new("lint").help("Which lint's page to load initially (optional)"),
-                ]),
-            Command::new("lint")
-                .about("Manually run clippy on a file or package")
-                .after_help(indoc! {"
-                    EXAMPLES
-                        Lint a single file:
-                            cargo dev lint tests/ui/attrs.rs
+#[derive(Parser)]
+#[command(name = "dev", about)]
+struct Dev {
+    #[command(subcommand)]
+    command: DevCommand,
+}
 
-                        Lint a package directory:
-                            cargo dev lint tests/ui-cargo/wildcard_dependencies/fail
-                            cargo dev lint ~/my-project
+#[derive(Subcommand)]
+enum DevCommand {
+    /// Bless the test output changes
+    Bless,
+    /// Runs the dogfood test
+    Dogfood {
+        #[arg(long)]
+        /// Apply the suggestions when possible
+        fix: bool,
+        #[arg(long, requires = "fix")]
+        /// Fix code even if the working directory has changes
+        allow_dirty: bool,
+        #[arg(long, requires = "fix")]
+        /// Fix code even if the working directory has staged changes
+        allow_staged: bool,
+    },
+    /// Run rustfmt on all projects and tests
+    Fmt {
+        #[arg(long)]
+        /// Use the rustfmt --check option
+        check: bool,
+        #[arg(short, long)]
+        /// Echo commands run
+        verbose: bool,
+    },
+    #[command(name = "update_lints")]
+    /// Updates lint registration and information from the source code
+    ///
+    /// Makes sure that: {n}
+    /// * the lint count in README.md is correct {n}
+    /// * the changelog contains markdown link references at the bottom {n}
+    /// * all lint groups include the correct lints {n}
+    /// * lint modules in `clippy_lints/*` are visible in `src/lib.rs` via `pub mod` {n}
+    /// * all lints are registered in the lint store
+    UpdateLints {
+        #[arg(long)]
+        /// Print a table of lints to STDOUT
+        ///
+        /// This does not include deprecated and internal lints. (Does not modify any files)
+        print_only: bool,
+        #[arg(long)]
+        /// Checks that `cargo dev update_lints` has been run. Used on CI.
+        check: bool,
+    },
+    #[command(name = "new_lint")]
+    /// Create a new lint and run `cargo dev update_lints`
+    NewLint {
+        #[arg(short, long, value_parser = ["early", "late"], conflicts_with = "type", default_value = "late")]
+        /// Specify whether the lint runs during the early or late pass
+        pass: String,
+        #[arg(
+            short,
+            long,
+            value_parser = |name: &str| Ok::<_, Infallible>(name.replace('-', "_")),
+        )]
+        /// Name of the new lint in snake case, ex: `fn_too_long`
+        name: String,
+        #[arg(
+            short,
+            long,
+            value_parser = [
+                "style",
+                "correctness",
+                "suspicious",
+                "complexity",
+                "perf",
+                "pedantic",
+                "restriction",
+                "cargo",
+                "nursery",
+                "internal",
+            ],
+            default_value = "nursery",
+        )]
+        /// What category the lint belongs to
+        category: String,
+        #[arg(long)]
+        /// What directory the lint belongs in
+        r#type: Option<String>,
+        #[arg(long)]
+        /// Add MSRV config code to the lint
+        msrv: bool,
+    },
+    /// Support for setting up your personal development environment
+    Setup(SetupCommand),
+    /// Support for removing changes done by the setup command
+    Remove(RemoveCommand),
+    /// Launch a local 'ALL the Clippy Lints' website in a browser
+    Serve {
+        #[arg(short, long, default_value = "8000")]
+        /// Local port for the http server
+        port: u16,
+        #[arg(long)]
+        /// Which lint's page to load initially (optional)
+        lint: Option<String>,
+    },
+    #[allow(clippy::doc_markdown)]
+    /// Manually run clippy on a file or package
+    ///
+    /// ## Examples
+    ///
+    /// Lint a single file: {n}
+    ///     cargo dev lint tests/ui/attrs.rs
+    ///
+    /// Lint a package directory: {n}
+    ///     cargo dev lint tests/ui-cargo/wildcard_dependencies/fail {n}
+    ///     cargo dev lint ~/my-project
+    ///
+    /// Run rustfix: {n}
+    ///     cargo dev lint ~/my-project -- --fix
+    ///
+    /// Set lint levels: {n}
+    ///     cargo dev lint file.rs -- -W clippy::pedantic {n}
+    ///     cargo dev lint ~/my-project -- -- -W clippy::pedantic
+    Lint {
+        /// The path to a file or package directory to lint
+        path: String,
+        /// Pass extra arguments to cargo/clippy-driver
+        args: Vec<String>,
+    },
+    #[command(name = "rename_lint")]
+    /// Rename a lint
+    RenameLint {
+        /// The name of the lint to rename
+        old_name: String,
+        #[arg(required_unless_present = "uplift")]
+        /// The new name of the lint
+        new_name: Option<String>,
+        #[arg(long)]
+        /// This lint will be uplifted into rustc
+        uplift: bool,
+    },
+    /// Deprecate the given lint
+    Deprecate {
+        /// The name of the lint to deprecate
+        name: String,
+        #[arg(long, short)]
+        /// The reason for deprecation
+        reason: Option<String>,
+    },
+}
 
-                        Run rustfix:
-                            cargo dev lint ~/my-project -- --fix
+#[derive(Args)]
+struct SetupCommand {
+    #[command(subcommand)]
+    subcommand: SetupSubcommand,
+}
 
-                        Set lint levels:
-                            cargo dev lint file.rs -- -W clippy::pedantic
-                            cargo dev lint ~/my-project -- -- -W clippy::pedantic
-                "})
-                .args([
-                    Arg::new("path")
-                        .required(true)
-                        .help("The path to a file or package directory to lint"),
-                    Arg::new("args")
-                        .action(ArgAction::Append)
-                        .help("Pass extra arguments to cargo/clippy-driver"),
-                ]),
-            Command::new("rename_lint").about("Renames the given lint").args([
-                Arg::new("old_name")
-                    .index(1)
-                    .required(true)
-                    .help("The name of the lint to rename"),
-                Arg::new("new_name")
-                    .index(2)
-                    .required_unless_present("uplift")
-                    .help("The new name of the lint"),
-                Arg::new("uplift")
-                    .long("uplift")
-                    .action(ArgAction::SetTrue)
-                    .help("This lint will be uplifted into rustc"),
-            ]),
-            Command::new("deprecate").about("Deprecates the given lint").args([
-                Arg::new("name")
-                    .index(1)
-                    .required(true)
-                    .help("The name of the lint to deprecate"),
-                Arg::new("reason")
-                    .long("reason")
-                    .short('r')
-                    .help("The reason for deprecation"),
-            ]),
-        ])
-        .get_matches()
+#[derive(Subcommand)]
+enum SetupSubcommand {
+    /// Alter dependencies so Intellij Rust can find rustc internals
+    Intellij {
+        #[arg(long)]
+        /// Remove the dependencies added with 'cargo dev setup intellij'
+        remove: bool,
+        #[arg(long, short, conflicts_with = "remove")]
+        /// The path to a rustc repo that will be used for setting the dependencies
+        repo_path: String,
+    },
+    /// Add a pre-commit git hook that formats your code to make it look pretty
+    GitHook {
+        #[arg(long)]
+        /// Remove the pre-commit hook added with 'cargo dev setup git-hook'
+        remove: bool,
+        #[arg(long, short)]
+        /// Forces the override of an existing git pre-commit hook
+        force_override: bool,
+    },
+    /// Install a rustup toolchain pointing to the local clippy build
+    Toolchain {
+        #[arg(long, short)]
+        /// Override an existing toolchain
+        force: bool,
+        #[arg(long, short)]
+        /// Point to --release clippy binary
+        release: bool,
+        #[arg(long, default_value = "clippy")]
+        /// Name of the toolchain
+        name: String,
+    },
+    /// Add several tasks to vscode for formatting, validation and testing
+    VscodeTasks {
+        #[arg(long)]
+        /// Remove the tasks added with 'cargo dev setup vscode-tasks'
+        remove: bool,
+        #[arg(long, short)]
+        /// Forces the override of existing vscode tasks
+        force_override: bool,
+    },
+}
+
+#[derive(Args)]
+struct RemoveCommand {
+    #[command(subcommand)]
+    subcommand: RemoveSubcommand,
+}
+
+#[derive(Subcommand)]
+enum RemoveSubcommand {
+    /// Remove the dependencies added with 'cargo dev setup intellij'
+    Intellij,
+    /// Remove the pre-commit git hook
+    GitHook,
+    /// Remove the tasks added with 'cargo dev setup vscode-tasks'
+    VscodeTasks,
 }
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index 2940d56..b6481dd 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -36,22 +36,16 @@
 /// # Errors
 ///
 /// This function errors out if the files couldn't be created or written to.
-pub fn create(
-    pass: &String,
-    lint_name: Option<&String>,
-    category: Option<&str>,
-    mut ty: Option<&str>,
-    msrv: bool,
-) -> io::Result<()> {
-    if category == Some("cargo") && ty.is_none() {
+pub fn create(pass: &str, name: &str, category: &str, mut ty: Option<&str>, msrv: bool) -> io::Result<()> {
+    if category == "cargo" && ty.is_none() {
         // `cargo` is a special category, these lints should always be in `clippy_lints/src/cargo`
         ty = Some("cargo");
     }
 
     let lint = LintData {
         pass,
-        name: lint_name.expect("`name` argument is validated by clap"),
-        category: category.expect("`category` argument is validated by clap"),
+        name,
+        category,
         ty,
         project_root: clippy_project_root(),
     };
diff --git a/src/tools/clippy/clippy_dev/src/serve.rs b/src/tools/clippy/clippy_dev/src/serve.rs
index ea925f6..4a4261d 100644
--- a/src/tools/clippy/clippy_dev/src/serve.rs
+++ b/src/tools/clippy/clippy_dev/src/serve.rs
@@ -8,7 +8,7 @@
 /// # Panics
 ///
 /// Panics if the python commands could not be spawned
-pub fn run(port: u16, lint: Option<&String>) -> ! {
+pub fn run(port: u16, lint: Option<String>) -> ! {
     let mut url = Some(match lint {
         None => format!("http://localhost:{port}"),
         Some(lint) => format!("http://localhost:{port}/#{lint}"),
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 625b133..4535390 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -314,7 +314,7 @@
 /// # Panics
 ///
 /// If a file path could not read from or written to
-pub fn deprecate(name: &str, reason: Option<&String>) {
+pub fn deprecate(name: &str, reason: Option<&str>) {
     fn finish(
         (lints, mut deprecated_lints, renamed_lints): (Vec<Lint>, Vec<DeprecatedLint>, Vec<RenamedLint>),
         name: &str,
@@ -335,7 +335,7 @@
         println!("note: you must run `cargo uitest` to update the test results");
     }
 
-    let reason = reason.map_or(DEFAULT_DEPRECATION_REASON, String::as_str);
+    let reason = reason.unwrap_or(DEFAULT_DEPRECATION_REASON);
     let name_lower = name.to_lowercase();
     let name_upper = name.to_uppercase();
 
diff --git a/src/tools/clippy/clippy_lints/src/assigning_clones.rs b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
index f0dafb1..e94a6f3 100644
--- a/src/tools/clippy/clippy_lints/src/assigning_clones.rs
+++ b/src/tools/clippy/clippy_lints/src/assigning_clones.rs
@@ -2,15 +2,15 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::HirNode;
 use clippy_utils::sugg::Sugg;
-use clippy_utils::{is_trait_method, path_to_local};
+use clippy_utils::{is_trait_method, local_is_initialized, path_to_local};
 use rustc_errors::Applicability;
-use rustc_hir::{self as hir, Expr, ExprKind, Node};
+use rustc_hir::{self as hir, Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{self, Instance, Mutability};
 use rustc_session::impl_lint_pass;
 use rustc_span::def_id::DefId;
 use rustc_span::symbol::sym;
-use rustc_span::ExpnKind;
+use rustc_span::{ExpnKind, SyntaxContext};
 
 declare_clippy_lint! {
     /// ### What it does
@@ -36,6 +36,7 @@
     /// Use instead:
     /// ```rust
     /// struct Thing;
+    ///
     /// impl Clone for Thing {
     ///     fn clone(&self) -> Self { todo!() }
     ///     fn clone_from(&mut self, other: &Self) { todo!() }
@@ -47,7 +48,7 @@
     /// ```
     #[clippy::version = "1.78.0"]
     pub ASSIGNING_CLONES,
-    perf,
+    pedantic,
     "assigning the result of cloning may be inefficient"
 }
 
@@ -67,7 +68,8 @@
 impl<'tcx> LateLintPass<'tcx> for AssigningClones {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, assign_expr: &'tcx Expr<'_>) {
         // Do not fire the lint in macros
-        let expn_data = assign_expr.span().ctxt().outer_expn_data();
+        let ctxt = assign_expr.span().ctxt();
+        let expn_data = ctxt.outer_expn_data();
         match expn_data.kind {
             ExpnKind::AstPass(_) | ExpnKind::Desugaring(_) | ExpnKind::Macro(..) => return,
             ExpnKind::Root => {},
@@ -82,7 +84,7 @@
         };
 
         if is_ok_to_suggest(cx, lhs, &call, &self.msrv) {
-            suggest(cx, assign_expr, lhs, &call);
+            suggest(cx, ctxt, assign_expr, lhs, &call);
         }
     }
 
@@ -163,9 +165,7 @@
         // TODO: This check currently bails if the local variable has no initializer.
         // That is overly conservative - the lint should fire even if there was no initializer,
         // but the variable has been initialized before `lhs` was evaluated.
-        if let Some(Node::LetStmt(local)) = cx.tcx.hir().parent_id_iter(local).next().map(|p| cx.tcx.hir_node(p))
-            && local.init.is_none()
-        {
+        if !local_is_initialized(cx, local) {
             return false;
         }
     }
@@ -222,14 +222,20 @@
     implemented_fns.contains_key(&provided_fn.def_id)
 }
 
-fn suggest<'tcx>(cx: &LateContext<'tcx>, assign_expr: &Expr<'tcx>, lhs: &Expr<'tcx>, call: &CallCandidate<'tcx>) {
+fn suggest<'tcx>(
+    cx: &LateContext<'tcx>,
+    ctxt: SyntaxContext,
+    assign_expr: &Expr<'tcx>,
+    lhs: &Expr<'tcx>,
+    call: &CallCandidate<'tcx>,
+) {
     span_lint_and_then(cx, ASSIGNING_CLONES, assign_expr.span, call.message(), |diag| {
         let mut applicability = Applicability::Unspecified;
 
         diag.span_suggestion(
             assign_expr.span,
             call.suggestion_msg(),
-            call.suggested_replacement(cx, lhs, &mut applicability),
+            call.suggested_replacement(cx, ctxt, lhs, &mut applicability),
             applicability,
         );
     });
@@ -275,6 +281,7 @@
     fn suggested_replacement(
         &self,
         cx: &LateContext<'tcx>,
+        ctxt: SyntaxContext,
         lhs: &Expr<'tcx>,
         applicability: &mut Applicability,
     ) -> String {
@@ -294,7 +301,7 @@
                         // Determine whether we need to reference the argument to clone_from().
                         let clone_receiver_type = cx.typeck_results().expr_ty(receiver);
                         let clone_receiver_adj_type = cx.typeck_results().expr_ty_adjusted(receiver);
-                        let mut arg_sugg = Sugg::hir_with_applicability(cx, receiver, "_", applicability);
+                        let mut arg_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability);
                         if clone_receiver_type != clone_receiver_adj_type {
                             // The receiver may have been a value type, so we need to add an `&` to
                             // be sure the argument to clone_from will be a reference.
@@ -312,7 +319,7 @@
                             Sugg::hir_with_applicability(cx, lhs, "_", applicability).mut_addr()
                         };
                         // The RHS had to be exactly correct before the call, there is no auto-deref for function calls.
-                        let rhs_sugg = Sugg::hir_with_applicability(cx, self_arg, "_", applicability);
+                        let rhs_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability);
 
                         format!("Clone::clone_from({self_sugg}, {rhs_sugg})")
                     },
@@ -341,11 +348,11 @@
 
                 match self.kind {
                     CallKind::MethodCall { receiver } => {
-                        let receiver_sugg = Sugg::hir_with_applicability(cx, receiver, "_", applicability);
+                        let receiver_sugg = Sugg::hir_with_context(cx, receiver, ctxt, "_", applicability);
                         format!("{receiver_sugg}.clone_into({rhs_sugg})")
                     },
                     CallKind::FunctionCall { self_arg, .. } => {
-                        let self_sugg = Sugg::hir_with_applicability(cx, self_arg, "_", applicability);
+                        let self_sugg = Sugg::hir_with_context(cx, self_arg, ctxt, "_", applicability);
                         format!("ToOwned::clone_into({self_sugg}, {rhs_sugg})")
                     },
                 }
diff --git a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
index 736ee48..40a1c4e 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/duplicated_attributes.rs
@@ -36,9 +36,10 @@
     }
     let Some(ident) = attr.ident() else { return };
     let name = ident.name;
-    if name == sym::doc || name == sym::cfg_attr {
+    if name == sym::doc || name == sym::cfg_attr || name == sym::rustc_on_unimplemented {
         // FIXME: Would be nice to handle `cfg_attr` as well. Only problem is to check that cfg
         // conditions are the same.
+        // `#[rustc_on_unimplemented]` contains duplicated subattributes, that's expected.
         return;
     }
     if let Some(direct_parent) = parent.last()
diff --git a/src/tools/clippy/clippy_lints/src/attrs/mod.rs b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
index 8f47bc7..39f4060 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/mod.rs
@@ -61,11 +61,21 @@
     ///
     /// This lint permits lint attributes for lints emitted on the items themself.
     /// For `use` items these lints are:
+    /// * ambiguous_glob_reexports
+    /// * dead_code
     /// * deprecated
+    /// * hidden_glob_reexports
     /// * unreachable_pub
-    /// * unused_imports
+    /// * unused
+    /// * unused_braces
+    /// * unused_import_braces
+    /// * clippy::disallowed_types
     /// * clippy::enum_glob_use
     /// * clippy::macro_use_imports
+    /// * clippy::module_name_repetitions
+    /// * clippy::redundant_pub_crate
+    /// * clippy::single_component_path_imports
+    /// * clippy::unsafe_removed_from_name
     /// * clippy::wildcard_imports
     ///
     /// For `extern crate` items these lints are:
diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
index 7575f50..f086823 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
@@ -2,6 +2,7 @@
 use super::{Attribute, USELESS_ATTRIBUTE};
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::{first_line_of_span, snippet_opt};
+use rustc_ast::NestedMetaItem;
 use rustc_errors::Applicability;
 use rustc_hir::{Item, ItemKind};
 use rustc_lint::{LateContext, LintContext};
@@ -20,26 +21,40 @@
                 for lint in lint_list {
                     match item.kind {
                         ItemKind::Use(..) => {
-                            if is_word(lint, sym::unused_imports)
-                                || is_word(lint, sym::deprecated)
-                                || is_word(lint, sym!(unreachable_pub))
-                                || is_word(lint, sym!(unused))
-                                || is_word(lint, sym!(unused_import_braces))
-                                || extract_clippy_lint(lint).map_or(false, |s| {
-                                    matches!(
-                                        s.as_str(),
-                                        "wildcard_imports"
-                                            | "enum_glob_use"
-                                            | "redundant_pub_crate"
-                                            | "macro_use_imports"
-                                            | "unsafe_removed_from_name"
-                                            | "module_name_repetitions"
-                                            | "single_component_path_imports"
-                                    )
-                                })
+                            if let NestedMetaItem::MetaItem(meta_item) = lint
+                                && meta_item.is_word()
+                                && let Some(ident) = meta_item.ident()
+                                && matches!(
+                                    ident.name.as_str(),
+                                    "ambiguous_glob_reexports"
+                                        | "dead_code"
+                                        | "deprecated"
+                                        | "hidden_glob_reexports"
+                                        | "unreachable_pub"
+                                        | "unused"
+                                        | "unused_braces"
+                                        | "unused_import_braces"
+                                        | "unused_imports"
+                                )
                             {
                                 return;
                             }
+
+                            if extract_clippy_lint(lint).is_some_and(|symbol| {
+                                matches!(
+                                    symbol.as_str(),
+                                    "wildcard_imports"
+                                        | "enum_glob_use"
+                                        | "redundant_pub_crate"
+                                        | "macro_use_imports"
+                                        | "unsafe_removed_from_name"
+                                        | "module_name_repetitions"
+                                        | "single_component_path_imports"
+                                        | "disallowed_types"
+                                )
+                            }) {
+                                return;
+                            }
                         },
                         ItemKind::ExternCrate(..) => {
                             if is_word(lint, sym::unused_imports) && skip_unused_imports {
diff --git a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs
index a3291c9..0d9eaac 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/lint_groups_priority.rs
@@ -49,7 +49,7 @@
 
 type LintTable = BTreeMap<Spanned<String>, Spanned<LintConfig>>;
 
-#[derive(Deserialize, Debug)]
+#[derive(Deserialize, Debug, Default)]
 struct Lints {
     #[serde(default)]
     rust: LintTable,
@@ -57,9 +57,18 @@
     clippy: LintTable,
 }
 
+#[derive(Deserialize, Debug, Default)]
+struct Workspace {
+    #[serde(default)]
+    lints: Lints,
+}
+
 #[derive(Deserialize, Debug)]
 struct CargoToml {
+    #[serde(default)]
     lints: Lints,
+    #[serde(default)]
+    workspace: Workspace,
 }
 
 #[derive(Default, Debug)]
@@ -164,5 +173,7 @@
 
         check_table(cx, cargo_toml.lints.rust, &rustc_groups, &file);
         check_table(cx, cargo_toml.lints.clippy, &clippy_groups, &file);
+        check_table(cx, cargo_toml.workspace.lints.rust, &rustc_groups, &file);
+        check_table(cx, cargo_toml.workspace.lints.clippy, &clippy_groups, &file);
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
index 2b6e17d..864489e 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs
@@ -255,8 +255,10 @@
 
 /// Peels binary operators such as [`BinOpKind::Mul`], [`BinOpKind::Div`] or [`BinOpKind::Rem`],
 /// where the result depends on:
+///
 /// - the number of negative values in the entire expression, or
 /// - the number of negative values on the left hand side of the expression.
+///
 /// Ignores overflow.
 ///
 ///
@@ -303,8 +305,10 @@
 }
 
 /// Peels binary operators such as [`BinOpKind::Add`], where the result depends on:
+///
 /// - all the expressions being positive, or
 /// - all the expressions being negative.
+///
 /// Ignores overflow.
 ///
 /// Expressions using other operators are preserved, so we can try to evaluate them later.
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 5ff7d8e..df2ef46 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -140,6 +140,7 @@
     crate::disallowed_names::DISALLOWED_NAMES_INFO,
     crate::disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS_INFO,
     crate::disallowed_types::DISALLOWED_TYPES_INFO,
+    crate::doc::DOC_LAZY_CONTINUATION_INFO,
     crate::doc::DOC_LINK_WITH_QUOTES_INFO,
     crate::doc::DOC_MARKDOWN_INFO,
     crate::doc::EMPTY_DOCS_INFO,
@@ -205,6 +206,7 @@
     crate::functions::MUST_USE_CANDIDATE_INFO,
     crate::functions::MUST_USE_UNIT_INFO,
     crate::functions::NOT_UNSAFE_PTR_ARG_DEREF_INFO,
+    crate::functions::RENAMED_FUNCTION_PARAMS_INFO,
     crate::functions::RESULT_LARGE_ERR_INFO,
     crate::functions::RESULT_UNIT_ERR_INFO,
     crate::functions::TOO_MANY_ARGUMENTS_INFO,
@@ -291,9 +293,11 @@
     crate::loops::SAME_ITEM_PUSH_INFO,
     crate::loops::SINGLE_ELEMENT_LOOP_INFO,
     crate::loops::UNUSED_ENUMERATE_INDEX_INFO,
+    crate::loops::WHILE_FLOAT_INFO,
     crate::loops::WHILE_IMMUTABLE_CONDITION_INFO,
     crate::loops::WHILE_LET_LOOP_INFO,
     crate::loops::WHILE_LET_ON_ITERATOR_INFO,
+    crate::macro_metavars_in_unsafe::MACRO_METAVARS_IN_UNSAFE_INFO,
     crate::macro_use::MACRO_USE_IMPORTS_INFO,
     crate::main_recursion::MAIN_RECURSION_INFO,
     crate::manual_assert::MANUAL_ASSERT_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
index 3f87ed8..b4290b6 100644
--- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
@@ -2,7 +2,7 @@
 use rustc_hir::{HirId, Item, ItemKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::{self, FieldDef, GenericArg, List};
+use rustc_middle::ty::{self, FieldDef};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
 
@@ -85,7 +85,7 @@
     }
 }
 
-fn is_zst<'tcx>(cx: &LateContext<'tcx>, field: &FieldDef, args: &'tcx List<GenericArg<'tcx>>) -> bool {
+fn is_zst<'tcx>(cx: &LateContext<'tcx>, field: &FieldDef, args: ty::GenericArgsRef<'tcx>) -> bool {
     let ty = field.ty(cx.tcx, args);
     if let Ok(layout) = cx.layout_of(ty) {
         layout.is_zst()
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index b936b28..c6aef9a 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -382,7 +382,7 @@
                                         cx,
                                         impl_ty,
                                         trait_id,
-                                        &args[..cx.tcx.generics_of(trait_id).params.len() - 1],
+                                        &args[..cx.tcx.generics_of(trait_id).own_params.len() - 1],
                                     )
                                 {
                                     false
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 42cd19f..2a64492 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -5,13 +5,13 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_expr, walk_fn, walk_item, FnKind, Visitor};
 use rustc_hir::{
-    self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Impl, Item, ItemKind, UnsafeSource, Unsafety,
+    self as hir, BlockCheckMode, BodyId, Expr, ExprKind, FnDecl, Safety, Impl, Item, ItemKind, UnsafeSource,
 };
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::traits::Reveal;
 use rustc_middle::ty::{
-    self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, ToPredicate, TraitPredicate, Ty, TyCtxt,
+    self, ClauseKind, GenericArgKind, GenericParamDefKind, ParamEnv, Upcast, TraitPredicate, Ty, TyCtxt,
 };
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
@@ -415,7 +415,7 @@
         }
 
         if let Some(header) = kind.header()
-            && header.unsafety == Unsafety::Unsafe
+            && header.safety == Safety::Unsafe
         {
             self.has_unsafe = true;
         }
@@ -480,7 +480,7 @@
     // Vec<(param_def, needs_eq)>
     let mut params = tcx
         .generics_of(did)
-        .params
+        .own_params
         .iter()
         .map(|p| (p, matches!(p.kind, GenericParamDefKind::Type { .. })))
         .collect::<Vec<_>>();
@@ -503,7 +503,7 @@
                     trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]),
                     polarity: ty::PredicatePolarity::Positive,
                 })
-                .to_predicate(tcx)
+                .upcast(tcx)
             }),
         )),
         Reveal::UserFacing,
diff --git a/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
new file mode 100644
index 0000000..38bc58a
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/doc/lazy_continuation.rs
@@ -0,0 +1,95 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use itertools::Itertools;
+use rustc_errors::{Applicability, SuggestionStyle};
+use rustc_lint::LateContext;
+use rustc_span::{BytePos, Span};
+use std::ops::Range;
+
+use super::DOC_LAZY_CONTINUATION;
+
+fn map_container_to_text(c: &super::Container) -> &'static str {
+    match c {
+        super::Container::Blockquote => "> ",
+        // numbered list can have up to nine digits, plus the dot, plus four spaces on either side
+        super::Container::List(indent) => &"                  "[0..*indent],
+    }
+}
+
+// TODO: Adjust the parameters as necessary
+pub(super) fn check(
+    cx: &LateContext<'_>,
+    doc: &str,
+    range: Range<usize>,
+    mut span: Span,
+    containers: &[super::Container],
+) {
+    if doc[range.clone()].contains('\t') {
+        // We don't do tab stops correctly.
+        return;
+    }
+
+    let ccount = doc[range.clone()].chars().filter(|c| *c == '>').count();
+    let blockquote_level = containers
+        .iter()
+        .filter(|c| matches!(c, super::Container::Blockquote))
+        .count();
+    let lcount = doc[range.clone()].chars().filter(|c| *c == ' ').count();
+    let list_indentation = containers
+        .iter()
+        .map(|c| {
+            if let super::Container::List(indent) = c {
+                *indent
+            } else {
+                0
+            }
+        })
+        .sum();
+    if ccount < blockquote_level || lcount < list_indentation {
+        let msg = if ccount < blockquote_level {
+            "doc quote missing `>` marker"
+        } else {
+            "doc list item missing indentation"
+        };
+        span_lint_and_then(cx, DOC_LAZY_CONTINUATION, span, msg, |diag| {
+            if ccount == 0 && blockquote_level == 0 {
+                // simpler suggestion style for indentation
+                let indent = list_indentation - lcount;
+                diag.span_suggestion_with_style(
+                    span.shrink_to_hi(),
+                    "indent this line",
+                    std::iter::repeat(" ").take(indent).join(""),
+                    Applicability::MaybeIncorrect,
+                    SuggestionStyle::ShowAlways,
+                );
+                diag.help("if this is supposed to be its own paragraph, add a blank line");
+                return;
+            }
+            let mut doc_start_range = &doc[range];
+            let mut suggested = String::new();
+            for c in containers {
+                let text = map_container_to_text(c);
+                if doc_start_range.starts_with(text) {
+                    doc_start_range = &doc_start_range[text.len()..];
+                    span = span
+                        .with_lo(span.lo() + BytePos(u32::try_from(text.len()).expect("text is not 2**32 or bigger")));
+                } else if matches!(c, super::Container::Blockquote)
+                    && let Some(i) = doc_start_range.find('>')
+                {
+                    doc_start_range = &doc_start_range[i + 1..];
+                    span =
+                        span.with_lo(span.lo() + BytePos(u32::try_from(i).expect("text is not 2**32 or bigger") + 1));
+                } else {
+                    suggested.push_str(text);
+                }
+            }
+            diag.span_suggestion_with_style(
+                span,
+                "add markers to start of line",
+                suggested,
+                Applicability::MachineApplicable,
+                SuggestionStyle::ShowAlways,
+            );
+            diag.help("if this not intended to be a quote at all, escape it with `\\>`");
+        });
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
index f935ae2..010fab8 100644
--- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
@@ -1,20 +1,19 @@
+use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_note};
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{is_doc_hidden, return_ty};
-use rustc_hir::{BodyId, FnSig, OwnerId, Unsafety};
+use rustc_hir::{BodyId, FnSig, OwnerId, Safety};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_span::{sym, Span};
 
-use super::{DocHeaders, MISSING_ERRORS_DOC, MISSING_PANICS_DOC, MISSING_SAFETY_DOC, UNNECESSARY_SAFETY_DOC};
-
 pub fn check(
     cx: &LateContext<'_>,
     owner_id: OwnerId,
     sig: FnSig<'_>,
     headers: DocHeaders,
     body_id: Option<BodyId>,
-    panic_span: Option<Span>,
+    panic_info: Option<(Span, bool)>,
     check_private_items: bool,
 ) {
     if !check_private_items && !cx.effective_visibilities.is_exported(owner_id.def_id) {
@@ -33,14 +32,14 @@
     }
 
     let span = cx.tcx.def_span(owner_id);
-    match (headers.safety, sig.header.unsafety) {
-        (false, Unsafety::Unsafe) => span_lint(
+    match (headers.safety, sig.header.safety) {
+        (false, Safety::Unsafe) => span_lint(
             cx,
             MISSING_SAFETY_DOC,
             span,
             "unsafe function's docs miss `# Safety` section",
         ),
-        (true, Unsafety::Normal) => span_lint(
+        (true, Safety::Safe) => span_lint(
             cx,
             UNNECESSARY_SAFETY_DOC,
             span,
@@ -48,13 +47,13 @@
         ),
         _ => (),
     }
-    if !headers.panics && panic_span.is_some() {
+    if !headers.panics && panic_info.map_or(false, |el| !el.1) {
         span_lint_and_note(
             cx,
             MISSING_PANICS_DOC,
             span,
             "docs for function which may panic missing `# Panics` section",
-            panic_span,
+            panic_info.map(|el| el.0),
             "first possible panic found here",
         );
     }
diff --git a/src/tools/clippy/clippy_lints/src/doc/mod.rs b/src/tools/clippy/clippy_lints/src/doc/mod.rs
index 4bced10..9f08973 100644
--- a/src/tools/clippy/clippy_lints/src/doc/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/mod.rs
@@ -1,18 +1,19 @@
+mod lazy_continuation;
 use clippy_utils::attrs::is_doc_hidden;
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::visitors::Visitable;
-use clippy_utils::{is_entrypoint_fn, is_trait_impl_item, method_chain_args};
+use clippy_utils::{in_constant, is_entrypoint_fn, is_trait_impl_item, method_chain_args};
 use pulldown_cmark::Event::{
     Code, End, FootnoteReference, HardBreak, Html, Rule, SoftBreak, Start, TaskListMarker, Text,
 };
-use pulldown_cmark::Tag::{BlockQuote, CodeBlock, Heading, Item, Link, Paragraph};
+use pulldown_cmark::Tag::{BlockQuote, CodeBlock, FootnoteDefinition, Heading, Item, Link, Paragraph};
 use pulldown_cmark::{BrokenLink, CodeBlockKind, CowStr, Options};
 use rustc_ast::ast::Attribute;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{AnonConst, Expr, ImplItemKind, ItemKind, Node, TraitItemKind, Unsafety};
+use rustc_hir::{AnonConst, Expr, ImplItemKind, ItemKind, Node, Safety, TraitItemKind};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
@@ -362,6 +363,63 @@
     "docstrings exist but documentation is empty"
 }
 
+declare_clippy_lint! {
+    /// ### What it does
+    ///
+    /// In CommonMark Markdown, the language used to write doc comments, a
+    /// paragraph nested within a list or block quote does not need any line
+    /// after the first one to be indented or marked. The specification calls
+    /// this a "lazy paragraph continuation."
+    ///
+    /// ### Why is this bad?
+    ///
+    /// This is easy to write but hard to read. Lazy continuations makes
+    /// unintended markers hard to see, and make it harder to deduce the
+    /// document's intended structure.
+    ///
+    /// ### Example
+    ///
+    /// This table is probably intended to have two rows,
+    /// but it does not. It has zero rows, and is followed by
+    /// a block quote.
+    /// ```no_run
+    /// /// Range | Description
+    /// /// ----- | -----------
+    /// /// >= 1  | fully opaque
+    /// /// < 1   | partially see-through
+    /// fn set_opacity(opacity: f32) {}
+    /// ```
+    ///
+    /// Fix it by escaping the marker:
+    /// ```no_run
+    /// /// Range | Description
+    /// /// ----- | -----------
+    /// /// \>= 1 | fully opaque
+    /// /// < 1   | partially see-through
+    /// fn set_opacity(opacity: f32) {}
+    /// ```
+    ///
+    /// This example is actually intended to be a list:
+    /// ```no_run
+    /// /// * Do nothing.
+    /// /// * Then do something. Whatever it is needs done,
+    /// /// it should be done right now.
+    /// # fn do_stuff() {}
+    /// ```
+    ///
+    /// Fix it by indenting the list contents:
+    /// ```no_run
+    /// /// * Do nothing.
+    /// /// * Then do something. Whatever it is needs done,
+    /// ///   it should be done right now.
+    /// # fn do_stuff() {}
+    /// ```
+    #[clippy::version = "1.80.0"]
+    pub DOC_LAZY_CONTINUATION,
+    style,
+    "require every line of a paragraph to be indented and marked"
+}
+
 #[derive(Clone)]
 pub struct Documentation {
     valid_idents: FxHashSet<String>,
@@ -388,6 +446,7 @@
     UNNECESSARY_SAFETY_DOC,
     SUSPICIOUS_DOC_COMMENTS,
     EMPTY_DOCS,
+    DOC_LAZY_CONTINUATION,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Documentation {
@@ -402,26 +461,26 @@
                     if !(is_entrypoint_fn(cx, item.owner_id.to_def_id()) || in_external_macro(cx.tcx.sess, item.span)) {
                         let body = cx.tcx.hir().body(body_id);
 
-                        let panic_span = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
+                        let panic_info = FindPanicUnwrap::find_span(cx, cx.tcx.typeck(item.owner_id), body.value);
                         missing_headers::check(
                             cx,
                             item.owner_id,
                             sig,
                             headers,
                             Some(body_id),
-                            panic_span,
+                            panic_info,
                             self.check_private_items,
                         );
                     }
                 },
                 ItemKind::Trait(_, unsafety, ..) => match (headers.safety, unsafety) {
-                    (false, Unsafety::Unsafe) => span_lint(
+                    (false, Safety::Unsafe) => span_lint(
                         cx,
                         MISSING_SAFETY_DOC,
                         cx.tcx.def_span(item.owner_id),
                         "docs for unsafe trait missing `# Safety` section",
                     ),
-                    (true, Unsafety::Normal) => span_lint(
+                    (true, Safety::Safe) => span_lint(
                         cx,
                         UNNECESSARY_SAFETY_DOC,
                         cx.tcx.def_span(item.owner_id),
@@ -551,6 +610,7 @@
         cx,
         valid_idents,
         parser.into_offset_iter(),
+        &doc,
         Fragments {
             fragments: &fragments,
             doc: &doc,
@@ -560,6 +620,11 @@
 
 const RUST_CODE: &[&str] = &["rust", "no_run", "should_panic", "compile_fail"];
 
+enum Container {
+    Blockquote,
+    List(usize),
+}
+
 /// Checks parsed documentation.
 /// This walks the "events" (think sections of markdown) produced by `pulldown_cmark`,
 /// so lints here will generally access that information.
@@ -569,6 +634,7 @@
     cx: &LateContext<'_>,
     valid_idents: &FxHashSet<String>,
     events: Events,
+    doc: &str,
     fragments: Fragments<'_>,
 ) -> DocHeaders {
     // true if a safety header was found
@@ -576,6 +642,7 @@
     let mut in_code = false;
     let mut in_link = None;
     let mut in_heading = false;
+    let mut in_footnote_definition = false;
     let mut is_rust = false;
     let mut no_test = false;
     let mut ignore = false;
@@ -586,7 +653,11 @@
     let mut code_level = 0;
     let mut blockquote_level = 0;
 
-    for (event, range) in events {
+    let mut containers = Vec::new();
+
+    let mut events = events.peekable();
+
+    while let Some((event, range)) = events.next() {
         match event {
             Html(tag) => {
                 if tag.starts_with("<code") {
@@ -599,8 +670,14 @@
                     blockquote_level -= 1;
                 }
             },
-            Start(BlockQuote) => blockquote_level += 1,
-            End(BlockQuote) => blockquote_level -= 1,
+            Start(BlockQuote) => {
+                blockquote_level += 1;
+                containers.push(Container::Blockquote);
+            },
+            End(BlockQuote) => {
+                blockquote_level -= 1;
+                containers.pop();
+            },
             Start(CodeBlock(ref kind)) => {
                 in_code = true;
                 if let CodeBlockKind::Fenced(lang) = kind {
@@ -633,6 +710,13 @@
                 if let Start(Heading(_, _, _)) = event {
                     in_heading = true;
                 }
+                if let Start(Item) = event {
+                    if let Some((_next_event, next_range)) = events.peek() {
+                        containers.push(Container::List(next_range.start - range.start));
+                    } else {
+                        containers.push(Container::List(0));
+                    }
+                }
                 ticks_unbalanced = false;
                 paragraph_range = range;
             },
@@ -640,6 +724,9 @@
                 if let End(Heading(_, _, _)) = event {
                     in_heading = false;
                 }
+                if let End(Item) = event {
+                    containers.pop();
+                }
                 if ticks_unbalanced && let Some(span) = fragments.span(cx, paragraph_range.clone()) {
                     span_lint_and_help(
                         cx,
@@ -658,8 +745,27 @@
                 }
                 text_to_check = Vec::new();
             },
+            Start(FootnoteDefinition(..)) => in_footnote_definition = true,
+            End(FootnoteDefinition(..)) => in_footnote_definition = false,
             Start(_tag) | End(_tag) => (), // We don't care about other tags
-            SoftBreak | HardBreak | TaskListMarker(_) | Code(_) | Rule => (),
+            SoftBreak | HardBreak => {
+                if !containers.is_empty()
+                    && let Some((next_event, next_range)) = events.peek()
+                    && let Some(next_span) = fragments.span(cx, next_range.clone())
+                    && let Some(span) = fragments.span(cx, range.clone())
+                    && !in_footnote_definition
+                    && !matches!(next_event, End(_))
+                {
+                    lazy_continuation::check(
+                        cx,
+                        doc,
+                        range.end..next_range.start,
+                        Span::new(span.hi(), next_span.lo(), span.ctxt(), span.parent()),
+                        &containers[..],
+                    );
+                }
+            },
+            TaskListMarker(_) | Code(_) | Rule => (),
             FootnoteReference(text) | Text(text) => {
                 paragraph_range.end = range.end;
                 ticks_unbalanced |= text.contains('`') && !in_code;
@@ -701,6 +807,7 @@
 
 struct FindPanicUnwrap<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
+    is_const: bool,
     panic_span: Option<Span>,
     typeck_results: &'tcx ty::TypeckResults<'tcx>,
 }
@@ -710,14 +817,15 @@
         cx: &'a LateContext<'tcx>,
         typeck_results: &'tcx ty::TypeckResults<'tcx>,
         body: impl Visitable<'tcx>,
-    ) -> Option<Span> {
+    ) -> Option<(Span, bool)> {
         let mut vis = Self {
             cx,
+            is_const: false,
             panic_span: None,
             typeck_results,
         };
         body.visit(&mut vis);
-        vis.panic_span
+        vis.panic_span.map(|el| (el, vis.is_const))
     }
 }
 
@@ -736,6 +844,7 @@
                     "assert" | "assert_eq" | "assert_ne"
                 )
             {
+                self.is_const = in_constant(self.cx, expr.hir_id);
                 self.panic_span = Some(macro_call.span);
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 386d4c3..8d6e277 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -1,7 +1,6 @@
 use clippy_utils::diagnostics::span_lint_hir;
 use rustc_hir::{intravisit, AssocItemKind, Body, FnDecl, HirId, HirIdSet, Impl, ItemKind, Node, Pat, PatKind};
 use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
-use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::layout::LayoutOf;
@@ -105,8 +104,9 @@
             too_large_for_stack: self.too_large_for_stack,
         };
 
-        let infcx = cx.tcx.infer_ctxt().build();
-        ExprUseVisitor::new(&mut v, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
+        ExprUseVisitor::for_clippy(cx, fn_def_id, &mut v)
+            .consume_body(body)
+            .into_ok();
 
         for node in v.set {
             span_lint_hir(
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 306a4a9..b58018c 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -5,7 +5,7 @@
 use clippy_utils::usage::{local_used_after_expr, local_used_in};
 use clippy_utils::{get_path_from_caller_to_method_type, is_adjusted, path_to_local, path_to_local_id};
 use rustc_errors::Applicability;
-use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, TyKind, Unsafety};
+use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, Param, PatKind, QPath, Safety, TyKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::{
@@ -146,7 +146,7 @@
                     ty::FnPtr(sig) => sig.skip_binder(),
                     ty::Closure(_, subs) => cx
                         .tcx
-                        .signature_unclosure(subs.as_closure().sig(), Unsafety::Normal)
+                        .signature_unclosure(subs.as_closure().sig(), Safety::Safe)
                         .skip_binder(),
                     _ => {
                         if typeck.type_dependent_def_id(body.value.hir_id).is_some()
@@ -154,7 +154,7 @@
                             && let output = typeck.expr_ty(body.value)
                             && let ty::Tuple(tys) = *subs.type_at(1).kind()
                         {
-                            cx.tcx.mk_fn_sig(tys, output, false, Unsafety::Normal, Abi::Rust)
+                            cx.tcx.mk_fn_sig(tys, output, false, Safety::Safe, Abi::Rust)
                         } else {
                             return;
                         }
@@ -241,11 +241,9 @@
 }
 
 fn check_sig<'tcx>(cx: &LateContext<'tcx>, closure: ClosureArgs<'tcx>, call_sig: FnSig<'_>) -> bool {
-    call_sig.unsafety == Unsafety::Normal
+    call_sig.safety == Safety::Safe
         && !has_late_bound_to_non_late_bound_regions(
-            cx.tcx
-                .signature_unclosure(closure.sig(), Unsafety::Normal)
-                .skip_binder(),
+            cx.tcx.signature_unclosure(closure.sig(), Safety::Safe).skip_binder(),
             call_sig,
         )
 }
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index 724e184..3c4a043 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -1,12 +1,12 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::macros::{find_format_args, format_args_inputs_span};
+use clippy_utils::macros::{format_args_inputs_span, FormatArgsStorage};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_expn_of, path_def_id};
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
 use rustc_hir::{BindingMode, Block, BlockCheckMode, Expr, ExprKind, Node, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
 use rustc_span::{sym, ExpnId};
 
 declare_clippy_lint! {
@@ -38,7 +38,17 @@
     "using the `write!()` family of functions instead of the `print!()` family of functions, when using the latter would work"
 }
 
-declare_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]);
+pub struct ExplicitWrite {
+    format_args: FormatArgsStorage,
+}
+
+impl ExplicitWrite {
+    pub fn new(format_args: FormatArgsStorage) -> Self {
+        Self { format_args }
+    }
+}
+
+impl_lint_pass!(ExplicitWrite => [EXPLICIT_WRITE]);
 
 impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
@@ -57,7 +67,7 @@
                 Some(sym::io_stderr) => ("stderr", "e"),
                 _ => return,
             };
-            let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else {
+            let Some(format_args) = self.format_args.get(cx, write_arg, ExpnId::root()) else {
                 return;
             };
 
@@ -83,7 +93,7 @@
             };
             let mut applicability = Applicability::MachineApplicable;
             let inputs_snippet =
-                snippet_with_applicability(cx, format_args_inputs_span(&format_args), "..", &mut applicability);
+                snippet_with_applicability(cx, format_args_inputs_span(format_args), "..", &mut applicability);
             span_lint_and_sugg(
                 cx,
                 EXPLICIT_WRITE,
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index 8a0cd15..0b248f7 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::macros::{find_format_arg_expr, find_format_args, root_macro_call_first_node};
+use clippy_utils::macros::{find_format_arg_expr, root_macro_call_first_node, FormatArgsStorage};
 use clippy_utils::source::{snippet_opt, snippet_with_context};
 use clippy_utils::sugg::Sugg;
 use rustc_ast::{FormatArgsPiece, FormatOptions, FormatTrait};
@@ -7,7 +7,7 @@
 use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty;
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
 use rustc_span::{sym, Span};
 
 declare_clippy_lint! {
@@ -39,13 +39,24 @@
     "useless use of `format!`"
 }
 
-declare_lint_pass!(UselessFormat => [USELESS_FORMAT]);
+#[allow(clippy::module_name_repetitions)]
+pub struct UselessFormat {
+    format_args: FormatArgsStorage,
+}
+
+impl UselessFormat {
+    pub fn new(format_args: FormatArgsStorage) -> Self {
+        Self { format_args }
+    }
+}
+
+impl_lint_pass!(UselessFormat => [USELESS_FORMAT]);
 
 impl<'tcx> LateLintPass<'tcx> for UselessFormat {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
         if let Some(macro_call) = root_macro_call_first_node(cx, expr)
             && cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id)
-            && let Some(format_args) = find_format_args(cx, expr, macro_call.expn)
+            && let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn)
         {
             let mut applicability = Applicability::MachineApplicable;
             let call_site = macro_call.span;
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 003a999..8611580 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -3,8 +3,8 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::is_diag_trait_item;
 use clippy_utils::macros::{
-    find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro,
-    is_format_macro, is_panic, matching_root_macro_call, root_macro_call_first_node, FormatParamUsage, MacroCall,
+    find_format_arg_expr, format_arg_removal_span, format_placeholder_format_span, is_assert_macro, is_format_macro,
+    is_panic, matching_root_macro_call, root_macro_call_first_node, FormatArgsStorage, FormatParamUsage, MacroCall,
 };
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::{implements_trait, is_type_lang_item};
@@ -167,15 +167,18 @@
     UNUSED_FORMAT_SPECS,
 ]);
 
+#[allow(clippy::struct_field_names)]
 pub struct FormatArgs {
+    format_args: FormatArgsStorage,
     msrv: Msrv,
     ignore_mixed: bool,
 }
 
 impl FormatArgs {
     #[must_use]
-    pub fn new(msrv: Msrv, allow_mixed_uninlined_format_args: bool) -> Self {
+    pub fn new(format_args: FormatArgsStorage, msrv: Msrv, allow_mixed_uninlined_format_args: bool) -> Self {
         Self {
+            format_args,
             msrv,
             ignore_mixed: allow_mixed_uninlined_format_args,
         }
@@ -186,13 +189,13 @@
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let Some(macro_call) = root_macro_call_first_node(cx, expr)
             && is_format_macro(cx, macro_call.def_id)
-            && let Some(format_args) = find_format_args(cx, expr, macro_call.expn)
+            && let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn)
         {
             let linter = FormatArgsExpr {
                 cx,
                 expr,
                 macro_call: &macro_call,
-                format_args: &format_args,
+                format_args,
                 ignore_mixed: self.ignore_mixed,
             };
 
diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs
index 0a52347..09be723 100644
--- a/src/tools/clippy/clippy_lints/src/format_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/format_impl.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::macros::{find_format_arg_expr, find_format_args, is_format_macro, root_macro_call_first_node};
+use clippy_utils::macros::{find_format_arg_expr, is_format_macro, root_macro_call_first_node, FormatArgsStorage};
 use clippy_utils::{get_parent_as_impl, is_diag_trait_item, path_to_local, peel_ref_operators};
 use rustc_ast::{FormatArgsPiece, FormatTrait};
 use rustc_errors::Applicability;
@@ -99,13 +99,15 @@
 
 #[derive(Default)]
 pub struct FormatImpl {
+    format_args: FormatArgsStorage,
     // Whether we are inside Display or Debug trait impl - None for neither
     format_trait_impl: Option<FormatTraitNames>,
 }
 
 impl FormatImpl {
-    pub fn new() -> Self {
+    pub fn new(format_args: FormatArgsStorage) -> Self {
         Self {
+            format_args,
             format_trait_impl: None,
         }
     }
@@ -129,6 +131,7 @@
         if let Some(format_trait_impl) = self.format_trait_impl {
             let linter = FormatImplExpr {
                 cx,
+                format_args: &self.format_args,
                 expr,
                 format_trait_impl,
             };
@@ -141,6 +144,7 @@
 
 struct FormatImplExpr<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
+    format_args: &'a FormatArgsStorage,
     expr: &'tcx Expr<'tcx>,
     format_trait_impl: FormatTraitNames,
 }
@@ -175,7 +179,7 @@
         if let Some(outer_macro) = root_macro_call_first_node(self.cx, self.expr)
             && let macro_def_id = outer_macro.def_id
             && is_format_macro(self.cx, macro_def_id)
-            && let Some(format_args) = find_format_args(self.cx, self.expr, outer_macro.expn)
+            && let Some(format_args) = self.format_args.get(self.cx, self.expr, outer_macro.expn)
         {
             for piece in &format_args.template {
                 if let FormatArgsPiece::Placeholder(placeholder) = piece
diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
index 633ed96..82ce501 100644
--- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
+++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_integer_literal;
 use clippy_utils::sugg::Sugg;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
+use clippy_utils::{in_constant, is_integer_literal};
 use rustc_errors::Applicability;
 use rustc_hir::{def, Expr, ExprKind, LangItem, PrimTy, QPath, TyKind};
 use rustc_lint::{LateContext, LateLintPass};
@@ -47,6 +47,9 @@
     fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) {
         if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind
             && let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind
+            // do not lint in constant context, because the suggestion won't work.
+            // NB: keep this check until a new `const_trait_impl` is available and stablized.
+            && !in_constant(cx, exp.hir_id)
 
             // check if the first part of the path is some integer primitive
             && let TyKind::Path(ty_qpath) = &ty.kind
diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
index 8ac17e1..7729c55 100644
--- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs
@@ -2,7 +2,7 @@
 use clippy_utils::source::snippet;
 use rustc_errors::Applicability;
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, ExprKind, FnDecl, ImplicitSelfKind, Unsafety};
+use rustc_hir::{Body, ExprKind, FnDecl, Safety, ImplicitSelfKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 use rustc_span::Span;
@@ -34,7 +34,7 @@
         ImplicitSelfKind::None => return,
     };
 
-    let name = if sig.header.unsafety == Unsafety::Unsafe {
+    let name = if sig.header.safety == Safety::Unsafe {
         name.strip_suffix("_unchecked").unwrap_or(name)
     } else {
         name
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index 9cc51fa..dfcaac9 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -2,15 +2,17 @@
 mod misnamed_getters;
 mod must_use;
 mod not_unsafe_ptr_arg_deref;
+mod renamed_function_params;
 mod result;
 mod too_many_arguments;
 mod too_many_lines;
 
+use clippy_utils::def_path_def_ids;
 use rustc_hir as hir;
 use rustc_hir::intravisit;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::impl_lint_pass;
-use rustc_span::def_id::LocalDefId;
+use rustc_span::def_id::{DefIdSet, LocalDefId};
 use rustc_span::Span;
 
 declare_clippy_lint! {
@@ -359,13 +361,51 @@
     "`impl Trait` is used in the function's parameters"
 }
 
-#[derive(Copy, Clone)]
-#[allow(clippy::struct_field_names)]
+declare_clippy_lint! {
+    /// ### What it does
+    /// Lints when the name of function parameters from trait impl is
+    /// different than its default implementation.
+    ///
+    /// ### Why is this bad?
+    /// Using the default name for parameters of a trait method is often
+    /// more desirable for consistency's sake.
+    ///
+    /// ### Example
+    /// ```rust
+    /// struct A(u32);
+    ///
+    /// impl PartialEq for A {
+    ///     fn eq(&self, b: &Self) -> bool {
+    ///         self.0 == b.0
+    ///     }
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```rust
+    /// struct A(u32);
+    ///
+    /// impl PartialEq for A {
+    ///     fn eq(&self, other: &Self) -> bool {
+    ///         self.0 == other.0
+    ///     }
+    /// }
+    /// ```
+    #[clippy::version = "1.74.0"]
+    pub RENAMED_FUNCTION_PARAMS,
+    restriction,
+    "renamed function parameters in trait implementation"
+}
+
+#[derive(Clone)]
 pub struct Functions {
     too_many_arguments_threshold: u64,
     too_many_lines_threshold: u64,
     large_error_threshold: u64,
     avoid_breaking_exported_api: bool,
+    allow_renamed_params_for: Vec<String>,
+    /// A set of resolved `def_id` of traits that are configured to allow
+    /// function params renaming.
+    trait_ids: DefIdSet,
 }
 
 impl Functions {
@@ -374,12 +414,15 @@
         too_many_lines_threshold: u64,
         large_error_threshold: u64,
         avoid_breaking_exported_api: bool,
+        allow_renamed_params_for: Vec<String>,
     ) -> Self {
         Self {
             too_many_arguments_threshold,
             too_many_lines_threshold,
             large_error_threshold,
             avoid_breaking_exported_api,
+            allow_renamed_params_for,
+            trait_ids: DefIdSet::default(),
         }
     }
 }
@@ -395,6 +438,7 @@
     RESULT_LARGE_ERR,
     MISNAMED_GETTERS,
     IMPL_TRAIT_IN_PARAMS,
+    RENAMED_FUNCTION_PARAMS,
 ]);
 
 impl<'tcx> LateLintPass<'tcx> for Functions {
@@ -424,6 +468,7 @@
         must_use::check_impl_item(cx, item);
         result::check_impl_item(cx, item, self.large_error_threshold);
         impl_trait_in_params::check_impl_item(cx, item);
+        renamed_function_params::check_impl_item(cx, item, &self.trait_ids);
     }
 
     fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
@@ -433,4 +478,12 @@
         result::check_trait_item(cx, item, self.large_error_threshold);
         impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api);
     }
+
+    fn check_crate(&mut self, cx: &LateContext<'tcx>) {
+        for path in &self.allow_renamed_params_for {
+            let path_segments: Vec<&str> = path.split("::").collect();
+            let ids = def_path_def_ids(cx, &path_segments);
+            self.trait_ids.extend(ids);
+        }
+    }
 }
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index 995dd78..b44a5f2 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -19,30 +19,30 @@
     body: &'tcx hir::Body<'tcx>,
     def_id: LocalDefId,
 ) {
-    let unsafety = match kind {
-        intravisit::FnKind::ItemFn(_, _, hir::FnHeader { unsafety, .. }) => unsafety,
-        intravisit::FnKind::Method(_, sig) => sig.header.unsafety,
+    let safety = match kind {
+        intravisit::FnKind::ItemFn(_, _, hir::FnHeader { safety, .. }) => safety,
+        intravisit::FnKind::Method(_, sig) => sig.header.safety,
         intravisit::FnKind::Closure => return,
     };
 
-    check_raw_ptr(cx, unsafety, decl, body, def_id);
+    check_raw_ptr(cx, safety, decl, body, def_id);
 }
 
 pub(super) fn check_trait_item<'tcx>(cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
     if let hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(eid)) = item.kind {
         let body = cx.tcx.hir().body(eid);
-        check_raw_ptr(cx, sig.header.unsafety, sig.decl, body, item.owner_id.def_id);
+        check_raw_ptr(cx, sig.header.safety, sig.decl, body, item.owner_id.def_id);
     }
 }
 
 fn check_raw_ptr<'tcx>(
     cx: &LateContext<'tcx>,
-    unsafety: hir::Unsafety,
+    safety: hir::Safety,
     decl: &'tcx hir::FnDecl<'tcx>,
     body: &'tcx hir::Body<'tcx>,
     def_id: LocalDefId,
 ) {
-    if unsafety == hir::Unsafety::Normal && cx.effective_visibilities.is_exported(def_id) {
+    if safety == hir::Safety::Safe && cx.effective_visibilities.is_exported(def_id) {
         let raw_ptrs = iter_input_pats(decl, body)
             .filter_map(|arg| raw_ptr_arg(cx, arg))
             .collect::<HirIdSet>();
@@ -58,7 +58,7 @@
                     },
                     hir::ExprKind::MethodCall(_, recv, args, _) => {
                         let def_id = typeck.type_dependent_def_id(e.hir_id).unwrap();
-                        if cx.tcx.fn_sig(def_id).skip_binder().skip_binder().unsafety == hir::Unsafety::Unsafe {
+                        if cx.tcx.fn_sig(def_id).skip_binder().skip_binder().safety == hir::Safety::Unsafe {
                             check_arg(cx, &raw_ptrs, recv);
                             for arg in args {
                                 check_arg(cx, &raw_ptrs, arg);
diff --git a/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
new file mode 100644
index 0000000..c7de038
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/functions/renamed_function_params.rs
@@ -0,0 +1,110 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use rustc_errors::{Applicability, MultiSpan};
+use rustc_hir::def_id::{DefId, DefIdSet};
+use rustc_hir::hir_id::OwnerId;
+use rustc_hir::{Impl, ImplItem, ImplItemKind, ImplItemRef, ItemKind, Node, TraitRef};
+use rustc_lint::LateContext;
+use rustc_span::symbol::{kw, Ident, Symbol};
+use rustc_span::Span;
+
+use super::RENAMED_FUNCTION_PARAMS;
+
+pub(super) fn check_impl_item(cx: &LateContext<'_>, item: &ImplItem<'_>, ignored_traits: &DefIdSet) {
+    if !item.span.from_expansion()
+        && let ImplItemKind::Fn(_, body_id) = item.kind
+        && let parent_node = cx.tcx.parent_hir_node(item.hir_id())
+        && let Node::Item(parent_item) = parent_node
+        && let ItemKind::Impl(Impl {
+            items,
+            of_trait: Some(trait_ref),
+            ..
+        }) = &parent_item.kind
+        && let Some(did) = trait_item_def_id_of_impl(items, item.owner_id)
+        && !is_from_ignored_trait(trait_ref, ignored_traits)
+    {
+        let mut param_idents_iter = cx.tcx.hir().body_param_names(body_id);
+        let mut default_param_idents_iter = cx.tcx.fn_arg_names(did).iter().copied();
+
+        let renames = RenamedFnArgs::new(&mut default_param_idents_iter, &mut param_idents_iter);
+        if !renames.0.is_empty() {
+            let multi_span = renames.multi_span();
+            let plural = if renames.0.len() == 1 { "" } else { "s" };
+            span_lint_and_then(
+                cx,
+                RENAMED_FUNCTION_PARAMS,
+                multi_span,
+                format!("renamed function parameter{plural} of trait impl"),
+                |diag| {
+                    diag.multipart_suggestion(
+                        format!("consider using the default name{plural}"),
+                        renames.0,
+                        Applicability::Unspecified,
+                    );
+                },
+            );
+        }
+    }
+}
+
+struct RenamedFnArgs(Vec<(Span, String)>);
+
+impl RenamedFnArgs {
+    /// Comparing between an iterator of default names and one with current names,
+    /// then collect the ones that got renamed.
+    fn new<I, T>(default_names: &mut I, current_names: &mut T) -> Self
+    where
+        I: Iterator<Item = Ident>,
+        T: Iterator<Item = Ident>,
+    {
+        let mut renamed: Vec<(Span, String)> = vec![];
+
+        debug_assert!(default_names.size_hint() == current_names.size_hint());
+        while let (Some(def_name), Some(cur_name)) = (default_names.next(), current_names.next()) {
+            let current_name = cur_name.name;
+            let default_name = def_name.name;
+            if is_unused_or_empty_symbol(current_name) || is_unused_or_empty_symbol(default_name) {
+                continue;
+            }
+            if current_name != default_name {
+                renamed.push((cur_name.span, default_name.to_string()));
+            }
+        }
+
+        Self(renamed)
+    }
+
+    fn multi_span(&self) -> MultiSpan {
+        self.0
+            .iter()
+            .map(|(span, _)| span)
+            .copied()
+            .collect::<Vec<Span>>()
+            .into()
+    }
+}
+
+fn is_unused_or_empty_symbol(symbol: Symbol) -> bool {
+    // FIXME: `body_param_names` currently returning empty symbols for `wild` as well,
+    // so we need to check if the symbol is empty first.
+    // Therefore the check of whether it's equal to [`kw::Underscore`] has no use for now,
+    // but it would be nice to keep it here just to be future-proof.
+    symbol.is_empty() || symbol == kw::Underscore || symbol.as_str().starts_with('_')
+}
+
+/// Get the [`trait_item_def_id`](ImplItemRef::trait_item_def_id) of a relevant impl item.
+fn trait_item_def_id_of_impl(items: &[ImplItemRef], target: OwnerId) -> Option<DefId> {
+    items.iter().find_map(|item| {
+        if item.id.owner_id == target {
+            item.trait_item_def_id
+        } else {
+            None
+        }
+    })
+}
+
+fn is_from_ignored_trait(of_trait: &TraitRef<'_>, ignored_traits: &DefIdSet) -> bool {
+    let Some(trait_did) = of_trait.trait_def_id() else {
+        return false;
+    };
+    ignored_traits.contains(&trait_did)
+}
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 18f4e51..192fb61 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -4,6 +4,7 @@
 use rustc_hir::{Body, FnDecl};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::print::PrintTraitRefExt;
 use rustc_middle::ty::{self, AliasTy, ClauseKind, PredicateKind};
 use rustc_session::declare_lint_pass;
 use rustc_span::def_id::LocalDefId;
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index 3bf8d61..dc935ed 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -148,7 +148,7 @@
     match args.get(index - 1) {
         Some(GenericArg::Type(ty)) => Some(lower_ty(tcx, ty)),
         Some(_) => None,
-        None => Some(tcx.type_of(generics.params[index].def_id).skip_binder()),
+        None => Some(tcx.type_of(generics.own_params[index].def_id).skip_binder()),
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index 157f610..9aedf5e 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::span_lint_and_help;
 use clippy_utils::ty::{implements_trait, is_type_lang_item};
 use clippy_utils::{return_ty, trait_ref_of_method};
-use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem, Unsafety};
+use rustc_hir::{GenericParamKind, ImplItem, ImplItemKind, LangItem, Safety};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::sym;
@@ -99,7 +99,7 @@
         if let ImplItemKind::Fn(ref signature, _) = impl_item.kind
             // #11201
             && let header = signature.header
-            && header.unsafety == Unsafety::Normal
+            && header.safety == Safety::Safe
             && header.abi == Abi::Rust
             && impl_item.ident.name == sym::to_string
             && let decl = signature.decl
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index c749a71..601d0e1 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -225,7 +225,7 @@
             && let ImplItemKind::Fn(sig, _) = item.kind
             && let FnRetTy::Return(ret) = sig.decl.output
             && is_nameable_in_impl_trait(ret)
-            && cx.tcx.generics_of(item_did).params.is_empty()
+            && cx.tcx.generics_of(item_did).is_own_empty()
             && sig.decl.implicit_self == expected_implicit_self
             && sig.decl.inputs.len() == 1
             && let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id())
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 2c44c38..3328d64 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -8,6 +8,7 @@
 #![feature(never_type)]
 #![feature(rustc_private)]
 #![feature(stmt_expr_attributes)]
+#![feature(unwrap_infallible)]
 #![recursion_limit = "512"]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![allow(
@@ -60,11 +61,6 @@
 #[macro_use]
 extern crate declare_clippy_lint;
 
-use std::collections::BTreeMap;
-
-use rustc_data_structures::fx::FxHashSet;
-use rustc_lint::{Lint, LintId};
-
 #[cfg(feature = "internal")]
 pub mod deprecated_lints;
 #[cfg_attr(feature = "internal", allow(clippy::missing_clippy_version_attribute))]
@@ -198,6 +194,7 @@
 mod lines_filter_map_ok;
 mod literal_representation;
 mod loops;
+mod macro_metavars_in_unsafe;
 mod macro_use;
 mod main_recursion;
 mod manual_assert;
@@ -384,6 +381,10 @@
 // end lints modules, do not remove this comment, it’s used in `update_lints`
 
 use clippy_config::{get_configuration_metadata, Conf};
+use clippy_utils::macros::FormatArgsStorage;
+use rustc_data_structures::fx::FxHashSet;
+use rustc_lint::{Lint, LintId};
+use std::collections::BTreeMap;
 
 /// Register all pre expansion lints
 ///
@@ -532,6 +533,7 @@
         allow_expect_in_tests,
         allow_mixed_uninlined_format_args,
         allow_one_hash_in_raw_strings,
+        allow_panic_in_tests,
         allow_print_in_tests,
         allow_private_module_inception,
         allow_unwrap_in_tests,
@@ -596,9 +598,11 @@
         ref allowed_duplicate_crates,
         allow_comparison_to_zero,
         ref allowed_prefixes,
+        ref allow_renamed_params_for,
 
         blacklisted_names: _,
         cyclomatic_complexity_threshold: _,
+        warn_unsafe_macro_metavars_in_private_macros,
     } = *conf;
     let msrv = || msrv.clone();
 
@@ -615,6 +619,14 @@
         }
     }
 
+    let format_args_storage = FormatArgsStorage::default();
+    let format_args = format_args_storage.clone();
+    store.register_early_pass(move || {
+        Box::new(utils::format_args_collector::FormatArgsCollector::new(
+            format_args.clone(),
+        ))
+    });
+
     // all the internal lints
     #[cfg(feature = "internal")]
     {
@@ -655,7 +667,6 @@
                 .collect(),
         ))
     });
-    store.register_early_pass(|| Box::<utils::format_args_collector::FormatArgsCollector>::default());
     store.register_late_pass(|_| Box::new(utils::dump_hir::DumpHir));
     store.register_late_pass(|_| Box::new(utils::author::Author));
     store.register_late_pass(move |_| {
@@ -697,6 +708,7 @@
     store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
     store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
     store.register_late_pass(move |_| Box::new(approx_const::ApproxConstant::new(msrv())));
+    let format_args = format_args_storage.clone();
     store.register_late_pass(move |_| {
         Box::new(methods::Methods::new(
             avoid_breaking_exported_api,
@@ -704,6 +716,7 @@
             allow_expect_in_tests,
             allow_unwrap_in_tests,
             allowed_dotfiles.clone(),
+            format_args.clone(),
         ))
     });
     store.register_late_pass(move |_| Box::new(matches::Matches::new(msrv())));
@@ -758,7 +771,7 @@
             allow_in_test: allow_useless_vec_in_tests,
         })
     });
-    store.register_late_pass(|_| Box::new(panic_unimplemented::PanicUnimplemented));
+    store.register_late_pass(move |_| Box::new(panic_unimplemented::PanicUnimplemented { allow_panic_in_tests }));
     store.register_late_pass(|_| Box::new(strings::StringLitAsBytes));
     store.register_late_pass(|_| Box::new(derive::Derive));
     store.register_late_pass(move |_| Box::new(derivable_impls::DerivableImpls::new(msrv())));
@@ -768,7 +781,8 @@
     store.register_late_pass(|_| Box::<regex::Regex>::default());
     store.register_late_pass(move |_| Box::new(copies::CopyAndPaste::new(ignore_interior_mutability.clone())));
     store.register_late_pass(|_| Box::new(copy_iterator::CopyIterator));
-    store.register_late_pass(|_| Box::new(format::UselessFormat));
+    let format_args = format_args_storage.clone();
+    store.register_late_pass(move |_| Box::new(format::UselessFormat::new(format_args.clone())));
     store.register_late_pass(|_| Box::new(swap::Swap));
     store.register_late_pass(|_| Box::new(overflow_check_conditional::OverflowCheckConditional));
     store.register_late_pass(|_| Box::<new_without_default::NewWithoutDefault>::default());
@@ -779,6 +793,7 @@
             too_many_lines_threshold,
             large_error_threshold,
             avoid_breaking_exported_api,
+            allow_renamed_params_for.clone(),
         ))
     });
     store.register_late_pass(move |_| Box::new(doc::Documentation::new(doc_valid_idents, check_private_items)));
@@ -792,7 +807,8 @@
     store.register_late_pass(|_| Box::new(partialeq_ne_impl::PartialEqNeImpl));
     store.register_late_pass(|_| Box::new(unused_io_amount::UnusedIoAmount));
     store.register_late_pass(move |_| Box::new(large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)));
-    store.register_late_pass(|_| Box::new(explicit_write::ExplicitWrite));
+    let format_args = format_args_storage.clone();
+    store.register_late_pass(move |_| Box::new(explicit_write::ExplicitWrite::new(format_args.clone())));
     store.register_late_pass(|_| Box::new(needless_pass_by_value::NeedlessPassByValue));
     store.register_late_pass(move |tcx| {
         Box::new(pass_by_ref_or_value::PassByRefOrValue::new(
@@ -834,7 +850,8 @@
     store.register_late_pass(move |_| Box::new(mut_key::MutableKeyType::new(ignore_interior_mutability.clone())));
     store.register_early_pass(|| Box::new(reference::DerefAddrOf));
     store.register_early_pass(|| Box::new(double_parens::DoubleParens));
-    store.register_late_pass(|_| Box::new(format_impl::FormatImpl::new()));
+    let format_args = format_args_storage.clone();
+    store.register_late_pass(move |_| Box::new(format_impl::FormatImpl::new(format_args.clone())));
     store.register_early_pass(|| Box::new(unsafe_removed_from_name::UnsafeNameRemoval));
     store.register_early_pass(|| Box::new(else_if_without_else::ElseIfWithoutElse));
     store.register_early_pass(|| Box::new(int_plus_one::IntPlusOne));
@@ -960,8 +977,14 @@
             accept_comment_above_attributes,
         ))
     });
-    store
-        .register_late_pass(move |_| Box::new(format_args::FormatArgs::new(msrv(), allow_mixed_uninlined_format_args)));
+    let format_args = format_args_storage.clone();
+    store.register_late_pass(move |_| {
+        Box::new(format_args::FormatArgs::new(
+            format_args.clone(),
+            msrv(),
+            allow_mixed_uninlined_format_args,
+        ))
+    });
     store.register_late_pass(|_| Box::new(trailing_empty_array::TrailingEmptyArray));
     store.register_early_pass(|| Box::new(octal_escapes::OctalEscapes));
     store.register_late_pass(|_| Box::new(needless_late_init::NeedlessLateInit));
@@ -972,7 +995,8 @@
     store.register_late_pass(|_| Box::new(default_union_representation::DefaultUnionRepresentation));
     store.register_late_pass(|_| Box::<only_used_in_recursion::OnlyUsedInRecursion>::default());
     store.register_late_pass(move |_| Box::new(dbg_macro::DbgMacro::new(allow_dbg_in_tests)));
-    store.register_late_pass(move |_| Box::new(write::Write::new(allow_print_in_tests)));
+    let format_args = format_args_storage.clone();
+    store.register_late_pass(move |_| Box::new(write::Write::new(format_args.clone(), allow_print_in_tests)));
     store.register_late_pass(move |_| {
         Box::new(cargo::Cargo {
             ignore_publish: cargo_ignore_publish,
@@ -1135,6 +1159,12 @@
     store.register_late_pass(|_| Box::new(zero_repeat_side_effects::ZeroRepeatSideEffects));
     store.register_late_pass(|_| Box::new(manual_unwrap_or_default::ManualUnwrapOrDefault));
     store.register_late_pass(|_| Box::new(integer_division_remainder_used::IntegerDivisionRemainderUsed));
+    store.register_late_pass(move |_| {
+        Box::new(macro_metavars_in_unsafe::ExprMetavarsInUnsafe {
+            warn_unsafe_macro_metavars_in_private_macros,
+            ..Default::default()
+        })
+    });
     // add lints here, do not remove this comment, it's used in `new_lint`
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index b5e39b3..3dcb050 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -17,6 +17,7 @@
 mod single_element_loop;
 mod unused_enumerate_index;
 mod utils;
+mod while_float;
 mod while_immutable_condition;
 mod while_let_loop;
 mod while_let_on_iterator;
@@ -418,6 +419,39 @@
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Checks for while loops comparing floating point values.
+    ///
+    /// ### Why is this bad?
+    /// If you increment floating point values, errors can compound,
+    /// so, use integers instead if possible.
+    ///
+    /// ### Known problems
+    /// The lint will catch all while loops comparing floating point
+    /// values without regarding the increment.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// let mut x = 0.0;
+    /// while x < 42.0 {
+    ///     x += 1.0;
+    /// }
+    /// ```
+    ///
+    /// Use instead:
+    /// ```no_run
+    /// let mut x = 0;
+    /// while x < 42 {
+    ///     x += 1;
+    /// }
+    /// ```
+    #[clippy::version = "1.80.0"]
+    pub WHILE_FLOAT,
+    nursery,
+    "while loops comaparing floating point values"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks whether a for loop is being used to push a constant
     /// value into a Vec.
     ///
@@ -706,6 +740,7 @@
     NEVER_LOOP,
     MUT_RANGE_BOUND,
     WHILE_IMMUTABLE_CONDITION,
+    WHILE_FLOAT,
     SAME_ITEM_PUSH,
     SINGLE_ELEMENT_LOOP,
     MISSING_SPIN_LOOP,
@@ -762,6 +797,7 @@
 
         if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) {
             while_immutable_condition::check(cx, condition, body);
+            while_float::check(cx, condition);
             missing_spin_loop::check(cx, condition, body);
             manual_while_let_some::check(cx, condition, body, span);
         }
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index 5047092..6c6a9a1 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -4,7 +4,6 @@
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Node, PatKind};
 use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
-use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty;
@@ -61,15 +60,9 @@
         span_low: None,
         span_high: None,
     };
-    let infcx = cx.tcx.infer_ctxt().build();
-    ExprUseVisitor::new(
-        &mut delegate,
-        &infcx,
-        body.hir_id.owner.def_id,
-        cx.param_env,
-        cx.typeck_results(),
-    )
-    .walk_expr(body);
+    ExprUseVisitor::for_clippy(cx, body.hir_id.owner.def_id, &mut delegate)
+        .walk_expr(body)
+        .into_ok();
 
     delegate.mutation_span()
 }
diff --git a/src/tools/clippy/clippy_lints/src/loops/while_float.rs b/src/tools/clippy/clippy_lints/src/loops/while_float.rs
new file mode 100644
index 0000000..cf62ce2
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/loops/while_float.rs
@@ -0,0 +1,20 @@
+use clippy_utils::diagnostics::span_lint;
+use rustc_hir::ExprKind;
+
+pub(super) fn check(cx: &rustc_lint::LateContext<'_>, condition: &rustc_hir::Expr<'_>) {
+    if let ExprKind::Binary(_op, left, right) = condition.kind
+        && is_float_type(cx, left)
+        && is_float_type(cx, right)
+    {
+        span_lint(
+            cx,
+            super::WHILE_FLOAT,
+            condition.span,
+            "while condition comparing floats",
+        );
+    }
+}
+
+fn is_float_type(cx: &rustc_lint::LateContext<'_>, expr: &rustc_hir::Expr<'_>) -> bool {
+    cx.typeck_results().expr_ty(expr).is_floating_point()
+}
diff --git a/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
new file mode 100644
index 0000000..aea3d26
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/macro_metavars_in_unsafe.rs
@@ -0,0 +1,256 @@
+use std::collections::btree_map::Entry;
+use std::collections::BTreeMap;
+
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::is_lint_allowed;
+use itertools::Itertools;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::{walk_block, walk_expr, walk_stmt, Visitor};
+use rustc_hir::{BlockCheckMode, Expr, ExprKind, HirId, Stmt, UnsafeSource};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::impl_lint_pass;
+use rustc_span::{sym, Span, SyntaxContext};
+
+declare_clippy_lint! {
+    /// ### What it does
+    /// Looks for macros that expand metavariables in an unsafe block.
+    ///
+    /// ### Why is this bad?
+    /// This hides an unsafe block and allows the user of the macro to write unsafe code without an explicit
+    /// unsafe block at callsite, making it possible to perform unsafe operations in seemingly safe code.
+    ///
+    /// The macro should be restructured so that these metavariables are referenced outside of unsafe blocks
+    /// and that the usual unsafety checks apply to the macro argument.
+    ///
+    /// This is usually done by binding it to a variable outside of the unsafe block
+    /// and then using that variable inside of the block as shown in the example, or by referencing it a second time
+    /// in a safe context, e.g. `if false { $expr }`.
+    ///
+    /// ### Known limitations
+    /// Due to how macros are represented in the compiler at the time Clippy runs its lints,
+    /// it's not possible to look for metavariables in macro definitions directly.
+    ///
+    /// Instead, this lint looks at expansions of macros.
+    /// This leads to false negatives for macros that are never actually invoked.
+    ///
+    /// By default, this lint is rather conservative and will only emit warnings on publicly-exported
+    /// macros from the same crate, because oftentimes private internal macros are one-off macros where
+    /// this lint would just be noise (e.g. macros that generate `impl` blocks).
+    /// The default behavior should help with preventing a high number of such false positives,
+    /// however it can be configured to also emit warnings in private macros if desired.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// /// Gets the first element of a slice
+    /// macro_rules! first {
+    ///     ($slice:expr) => {
+    ///         unsafe {
+    ///             let slice = $slice; // ⚠️ expansion inside of `unsafe {}`
+    ///
+    ///             assert!(!slice.is_empty());
+    ///             // SAFETY: slice is checked to have at least one element
+    ///             slice.first().unwrap_unchecked()
+    ///         }
+    ///     }
+    /// }
+    ///
+    /// assert_eq!(*first!(&[1i32]), 1);
+    ///
+    /// // This will compile as a consequence (note the lack of `unsafe {}`)
+    /// assert_eq!(*first!(std::hint::unreachable_unchecked() as &[i32]), 1);
+    /// ```
+    /// Use instead:
+    /// ```compile_fail
+    /// macro_rules! first {
+    ///     ($slice:expr) => {{
+    ///         let slice = $slice; // ✅ outside of `unsafe {}`
+    ///         unsafe {
+    ///             assert!(!slice.is_empty());
+    ///             // SAFETY: slice is checked to have at least one element
+    ///             slice.first().unwrap_unchecked()
+    ///         }
+    ///     }}
+    /// }
+    ///
+    /// assert_eq!(*first!(&[1]), 1);
+    ///
+    /// // This won't compile:
+    /// assert_eq!(*first!(std::hint::unreachable_unchecked() as &[i32]), 1);
+    /// ```
+    #[clippy::version = "1.80.0"]
+    pub MACRO_METAVARS_IN_UNSAFE,
+    suspicious,
+    "expanding macro metavariables in an unsafe block"
+}
+impl_lint_pass!(ExprMetavarsInUnsafe => [MACRO_METAVARS_IN_UNSAFE]);
+
+#[derive(Clone, Debug)]
+pub enum MetavarState {
+    ReferencedInUnsafe { unsafe_blocks: Vec<HirId> },
+    ReferencedInSafe,
+}
+
+#[derive(Default)]
+pub struct ExprMetavarsInUnsafe {
+    pub warn_unsafe_macro_metavars_in_private_macros: bool,
+    /// A metavariable can be expanded more than once, potentially across multiple bodies, so it
+    /// requires some state kept across HIR nodes to make it possible to delay a warning
+    /// and later undo:
+    ///
+    /// ```ignore
+    /// macro_rules! x {
+    ///     ($v:expr) => {
+    ///         unsafe { $v; } // unsafe context, it might be possible to emit a warning here, so add it to the map
+    ///
+    ///         $v;            // `$v` expanded another time but in a safe context, set to ReferencedInSafe to suppress
+    ///     }
+    /// }
+    /// ```
+    pub metavar_expns: BTreeMap<Span, MetavarState>,
+}
+
+struct BodyVisitor<'a, 'tcx> {
+    /// Stack of unsafe blocks -- the top item always represents the last seen unsafe block from
+    /// within a relevant macro.
+    macro_unsafe_blocks: Vec<HirId>,
+    /// When this is >0, it means that the node currently being visited is "within" a
+    /// macro definition. This is not necessary for correctness, it merely helps reduce the number
+    /// of spans we need to insert into the map, since only spans from macros are relevant.
+    expn_depth: u32,
+    cx: &'a LateContext<'tcx>,
+    lint: &'a mut ExprMetavarsInUnsafe,
+}
+
+fn is_public_macro(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
+    (cx.effective_visibilities.is_exported(def_id) || cx.tcx.has_attr(def_id, sym::macro_export))
+        && !cx.tcx.is_doc_hidden(def_id)
+}
+
+impl<'a, 'tcx> Visitor<'tcx> for BodyVisitor<'a, 'tcx> {
+    fn visit_stmt(&mut self, s: &'tcx Stmt<'tcx>) {
+        let from_expn = s.span.from_expansion();
+        if from_expn {
+            self.expn_depth += 1;
+        }
+        walk_stmt(self, s);
+        if from_expn {
+            self.expn_depth -= 1;
+        }
+    }
+
+    fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) {
+        let ctxt = e.span.ctxt();
+
+        if let ExprKind::Block(block, _) = e.kind
+            && let BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided) = block.rules
+            && !ctxt.is_root()
+            && let Some(macro_def_id) = ctxt.outer_expn_data().macro_def_id
+            && let Some(macro_def_id) = macro_def_id.as_local()
+            && (self.lint.warn_unsafe_macro_metavars_in_private_macros || is_public_macro(self.cx, macro_def_id))
+        {
+            self.macro_unsafe_blocks.push(block.hir_id);
+            walk_block(self, block);
+            self.macro_unsafe_blocks.pop();
+        } else if ctxt.is_root() && self.expn_depth > 0 {
+            let unsafe_block = self.macro_unsafe_blocks.last().copied();
+
+            match (self.lint.metavar_expns.entry(e.span), unsafe_block) {
+                (Entry::Vacant(e), None) => {
+                    e.insert(MetavarState::ReferencedInSafe);
+                },
+                (Entry::Vacant(e), Some(unsafe_block)) => {
+                    e.insert(MetavarState::ReferencedInUnsafe {
+                        unsafe_blocks: vec![unsafe_block],
+                    });
+                },
+                (Entry::Occupied(mut e), None) => {
+                    if let MetavarState::ReferencedInUnsafe { .. } = *e.get() {
+                        e.insert(MetavarState::ReferencedInSafe);
+                    }
+                },
+                (Entry::Occupied(mut e), Some(unsafe_block)) => {
+                    if let MetavarState::ReferencedInUnsafe { unsafe_blocks } = e.get_mut()
+                        && !unsafe_blocks.contains(&unsafe_block)
+                    {
+                        unsafe_blocks.push(unsafe_block);
+                    }
+                },
+            }
+
+            // NB: No need to visit descendant nodes. They're guaranteed to represent the same
+            // metavariable
+        } else {
+            walk_expr(self, e);
+        }
+    }
+}
+
+impl<'tcx> LateLintPass<'tcx> for ExprMetavarsInUnsafe {
+    fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx rustc_hir::Body<'tcx>) {
+        if is_lint_allowed(cx, MACRO_METAVARS_IN_UNSAFE, body.value.hir_id) {
+            return;
+        }
+
+        // This BodyVisitor is separate and not part of the lint pass because there is no
+        // `check_stmt_post` on `(Late)LintPass`, which we'd need to detect when we're leaving a macro span
+
+        let mut vis = BodyVisitor {
+            #[expect(clippy::bool_to_int_with_if)] // obfuscates the meaning
+            expn_depth: if body.value.span.from_expansion() { 1 } else { 0 },
+            macro_unsafe_blocks: Vec::new(),
+            lint: self,
+            cx
+        };
+        vis.visit_body(body);
+    }
+
+    fn check_crate_post(&mut self, cx: &LateContext<'tcx>) {
+        // Aggregate all unsafe blocks from all spans:
+        // ```
+        // macro_rules! x {
+        //   ($w:expr, $x:expr, $y:expr) => { $w; unsafe { $w; $x; }; unsafe { $x; $y; }; }
+        // }
+        // $w: []  (unsafe#0 is never added because it was referenced in a safe context)
+        // $x: [unsafe#0, unsafe#1]
+        // $y: [unsafe#1]
+        // ```
+        // We want to lint unsafe blocks #0 and #1
+        let bad_unsafe_blocks = self
+            .metavar_expns
+            .iter()
+            .filter_map(|(_, state)| match state {
+                MetavarState::ReferencedInUnsafe { unsafe_blocks } => Some(unsafe_blocks.as_slice()),
+                MetavarState::ReferencedInSafe => None,
+            })
+            .flatten()
+            .copied()
+            .map(|id| {
+                // Remove the syntax context to hide "in this macro invocation" in the diagnostic.
+                // The invocation doesn't matter. Also we want to dedupe by the unsafe block and not by anything
+                // related to the callsite.
+                let span = cx.tcx.hir().span(id);
+
+                (id, Span::new(span.lo(), span.hi(), SyntaxContext::root(), None))
+            })
+            .dedup_by(|&(_, a), &(_, b)| a == b);
+
+        for (id, span) in bad_unsafe_blocks {
+            span_lint_hir_and_then(
+                cx,
+                MACRO_METAVARS_IN_UNSAFE,
+                id,
+                span,
+                "this macro expands metavariables in an unsafe block",
+                |diag| {
+                    diag.note("this allows the user of the macro to write unsafe code outside of an unsafe block");
+                    diag.help(
+                            "consider expanding any metavariables outside of this block, e.g. by storing them in a variable",
+                        );
+                    diag.help(
+                            "... or also expand referenced metavariables in a safe context to require an unsafe block at callsite",
+                        );
+                },
+            );
+        }
+    }
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index d76b94e..83c16d4 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -1,10 +1,9 @@
-use crate::rustc_lint::LintContext;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::macros::{is_panic, root_macro_call};
 use clippy_utils::{is_else_clause, is_parent_stmt, peel_blocks_with_stmt, span_extract_comment, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::{Expr, ExprKind, UnOp};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::declare_lint_pass;
 
 declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index 1eadc20..e2ab441 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -611,15 +611,22 @@
 
 /// The clamp meta pattern is a pattern shared between many (but not all) patterns.
 /// In summary, this pattern consists of two if statements that meet many criteria,
+///
 /// - binary operators that are one of [`>`, `<`, `>=`, `<=`].
+///
 /// - Both binary statements must have a shared argument
+///
 ///     - Which can appear on the left or right side of either statement
+///
 ///     - The binary operators must define a finite range for the shared argument. To put this in
 ///       the terms of Rust `std` library, the following ranges are acceptable
+///
 ///         - `Range`
 ///         - `RangeInclusive`
+///
 ///       And all other range types are not accepted. For the purposes of `clamp` it's irrelevant
 ///       whether the range is inclusive or not, the output is the same.
+///
 /// - The result of each if statement must be equal to the argument unique to that if statement. The
 ///   result can not be the shared argument in either case.
 fn is_clamp_meta_pattern<'tcx>(
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index cd61e73..da8c918 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_hir_and_then;
-use clippy_utils::source::snippet;
+use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_lint_allowed, path_to_local, search_same, SpanlessEq, SpanlessHash};
 use core::cmp::Ordering;
 use core::{iter, slice};
@@ -9,9 +9,9 @@
 use rustc_hir::def_id::DefId;
 use rustc_hir::{Arm, Expr, ExprKind, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatKind, RangeEnd};
 use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
-use rustc_lint::LateContext;
+use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty;
-use rustc_span::{ErrorGuaranteed, Symbol};
+use rustc_span::{ErrorGuaranteed, Span, Symbol};
 
 use super::MATCH_SAME_ARMS;
 
@@ -110,20 +110,22 @@
             && check_same_body()
     };
 
+    let mut appl = Applicability::MaybeIncorrect;
     let indexed_arms: Vec<(usize, &Arm<'_>)> = arms.iter().enumerate().collect();
     for (&(i, arm1), &(j, arm2)) in search_same(&indexed_arms, hash, eq) {
         if matches!(arm2.pat.kind, PatKind::Wild) {
             if !cx.tcx.features().non_exhaustive_omitted_patterns_lint
                 || is_lint_allowed(cx, NON_EXHAUSTIVE_OMITTED_PATTERNS, arm2.hir_id)
             {
+                let arm_span = adjusted_arm_span(cx, arm1.span);
                 span_lint_hir_and_then(
                     cx,
                     MATCH_SAME_ARMS,
                     arm1.hir_id,
-                    arm1.span,
+                    arm_span,
                     "this match arm has an identical body to the `_` wildcard arm",
                     |diag| {
-                        diag.span_suggestion(arm1.span, "try removing the arm", "", Applicability::MaybeIncorrect)
+                        diag.span_suggestion(arm_span, "try removing the arm", "", appl)
                             .help("or try changing either arm body")
                             .span_note(arm2.span, "`_` wildcard arm here");
                     },
@@ -144,23 +146,36 @@
                 keep_arm.span,
                 "this match arm has an identical body to another arm",
                 |diag| {
-                    let move_pat_snip = snippet(cx, move_arm.pat.span, "<pat2>");
-                    let keep_pat_snip = snippet(cx, keep_arm.pat.span, "<pat1>");
+                    let move_pat_snip = snippet_with_applicability(cx, move_arm.pat.span, "<pat2>", &mut appl);
+                    let keep_pat_snip = snippet_with_applicability(cx, keep_arm.pat.span, "<pat1>", &mut appl);
 
                     diag.span_suggestion(
                         keep_arm.pat.span,
-                        "try merging the arm patterns",
+                        "or try merging the arm patterns",
                         format!("{keep_pat_snip} | {move_pat_snip}"),
-                        Applicability::MaybeIncorrect,
+                        appl,
                     )
-                    .help("or try changing either arm body")
-                    .span_note(move_arm.span, "other arm here");
+                    .span_suggestion(
+                        adjusted_arm_span(cx, move_arm.span),
+                        "and remove this obsolete arm",
+                        "",
+                        appl,
+                    )
+                    .help("try changing either arm body");
                 },
             );
         }
     }
 }
 
+/// Extend arm's span to include the comma and whitespaces after it.
+fn adjusted_arm_span(cx: &LateContext<'_>, span: Span) -> Span {
+    let source_map = cx.sess().source_map();
+    source_map
+        .span_extend_while(span, |c| c == ',' || c.is_ascii_whitespace())
+        .unwrap_or(span)
+}
+
 #[derive(Clone, Copy)]
 enum NormalizedPat<'a> {
     Wild,
diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
index 10c3203..6ac0705 100644
--- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs
@@ -6,7 +6,7 @@
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{Arm, Expr, ExprKind, MatchSource};
 use rustc_lint::{LateContext, LintContext};
-use rustc_middle::ty::{GenericArgKind, Ty, TypeAndMut};
+use rustc_middle::ty::{GenericArgKind, Ty};
 use rustc_span::Span;
 
 use super::SIGNIFICANT_DROP_IN_SCRUTINEE;
@@ -115,45 +115,60 @@
         }
     }
 
-    fn get_type(&self, ex: &'tcx Expr<'_>) -> Ty<'tcx> {
-        self.cx.typeck_results().expr_ty(ex)
+    fn is_sig_drop_expr(&mut self, ex: &'tcx Expr<'_>) -> bool {
+        !ex.is_syntactic_place_expr() && self.has_sig_drop_attr(self.cx.typeck_results().expr_ty(ex))
     }
 
-    fn has_seen_type(&mut self, ty: Ty<'tcx>) -> bool {
-        !self.seen_types.insert(ty)
+    fn has_sig_drop_attr(&mut self, ty: Ty<'tcx>) -> bool {
+        self.seen_types.clear();
+        self.has_sig_drop_attr_impl(ty)
     }
 
-    fn has_sig_drop_attr(&mut self, cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+    fn has_sig_drop_attr_impl(&mut self, ty: Ty<'tcx>) -> bool {
         if let Some(adt) = ty.ty_adt_def() {
-            if get_attr(cx.sess(), cx.tcx.get_attrs_unchecked(adt.did()), "has_significant_drop").count() > 0 {
+            if get_attr(
+                self.cx.sess(),
+                self.cx.tcx.get_attrs_unchecked(adt.did()),
+                "has_significant_drop",
+            )
+            .count()
+                > 0
+            {
                 return true;
             }
         }
 
-        match ty.kind() {
-            rustc_middle::ty::Adt(a, b) => {
-                for f in a.all_fields() {
-                    let ty = f.ty(cx.tcx, b);
-                    if !self.has_seen_type(ty) && self.has_sig_drop_attr(cx, ty) {
-                        return true;
-                    }
-                }
-
-                for generic_arg in *b {
-                    if let GenericArgKind::Type(ty) = generic_arg.unpack() {
-                        if self.has_sig_drop_attr(cx, ty) {
-                            return true;
-                        }
-                    }
-                }
-                false
-            },
-            rustc_middle::ty::Array(ty, _)
-            | rustc_middle::ty::RawPtr(ty, _)
-            | rustc_middle::ty::Ref(_, ty, _)
-            | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr(cx, *ty),
-            _ => false,
+        if !self.seen_types.insert(ty) {
+            return false;
         }
+
+        let result = match ty.kind() {
+            rustc_middle::ty::Adt(adt, args) => {
+                // if some field has significant drop,
+                adt.all_fields()
+                    .map(|field| field.ty(self.cx.tcx, args))
+                    .any(|ty| self.has_sig_drop_attr_impl(ty))
+                    // or if there is no generic lifetime and..
+                    // (to avoid false positive on `Ref<'a, MutexGuard<Foo>>`)
+                    || (args
+                        .iter()
+                        .all(|arg| !matches!(arg.unpack(), GenericArgKind::Lifetime(_)))
+                        // some generic parameter has significant drop
+                        // (to avoid false negative on `Box<MutexGuard<Foo>>`)
+                        && args
+                            .iter()
+                            .filter_map(|arg| match arg.unpack() {
+                                GenericArgKind::Type(ty) => Some(ty),
+                                _ => None,
+                            })
+                            .any(|ty| self.has_sig_drop_attr_impl(ty)))
+            },
+            rustc_middle::ty::Tuple(tys) => tys.iter().any(|ty| self.has_sig_drop_attr_impl(ty)),
+            rustc_middle::ty::Array(ty, _) | rustc_middle::ty::Slice(ty) => self.has_sig_drop_attr_impl(*ty),
+            _ => false,
+        };
+
+        result
     }
 }
 
@@ -232,11 +247,11 @@
         if self.current_sig_drop.is_some() {
             return;
         }
-        let ty = self.sig_drop_checker.get_type(expr);
+        let ty = self.cx.typeck_results().expr_ty(expr);
         if ty.is_ref() {
-            // We checked that the type was ref, so builtin_deref will return Some TypeAndMut,
-            // but let's avoid any chance of an ICE
-            if let Some(TypeAndMut { ty, .. }) = ty.builtin_deref(true) {
+            // We checked that the type was ref, so builtin_deref will return Some,
+            // but let's avoid any chance of an ICE.
+            if let Some(ty) = ty.builtin_deref(true) {
                 if ty.is_trivially_pure_clone_copy() {
                     self.replace_current_sig_drop(expr.span, false, LintSuggestion::MoveAndDerefToCopy);
                 } else if allow_move_and_clone {
@@ -279,11 +294,7 @@
 
 impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx Expr<'_>) {
-        if !self.is_chain_end
-            && self
-                .sig_drop_checker
-                .has_sig_drop_attr(self.cx, self.sig_drop_checker.get_type(ex))
-        {
+        if !self.is_chain_end && self.sig_drop_checker.is_sig_drop_expr(ex) {
             self.has_significant_drop = true;
             return;
         }
@@ -387,10 +398,7 @@
 
 impl<'a, 'tcx> Visitor<'tcx> for ArmSigDropHelper<'a, 'tcx> {
     fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
-        if self
-            .sig_drop_checker
-            .has_sig_drop_attr(self.sig_drop_checker.cx, self.sig_drop_checker.get_type(ex))
-        {
+        if self.sig_drop_checker.is_sig_drop_expr(ex) {
             self.found_sig_drop_spans.insert(ex.span);
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index fba7685..c9f56e1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::macros::{find_format_args, format_args_inputs_span, root_macro_call_first_node};
+use clippy_utils::macros::{format_args_inputs_span, root_macro_call_first_node, FormatArgsStorage};
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
 use rustc_errors::Applicability;
@@ -16,6 +16,7 @@
 #[allow(clippy::too_many_lines)]
 pub(super) fn check<'tcx>(
     cx: &LateContext<'tcx>,
+    format_args_storage: &FormatArgsStorage,
     expr: &hir::Expr<'_>,
     method_span: Span,
     name: &str,
@@ -134,9 +135,9 @@
     // Special handling for `format!` as arg_root
     if let Some(macro_call) = root_macro_call_first_node(cx, arg_root) {
         if cx.tcx.is_diagnostic_item(sym::format_macro, macro_call.def_id)
-            && let Some(format_args) = find_format_args(cx, arg_root, macro_call.expn)
+            && let Some(format_args) = format_args_storage.get(cx, arg_root, macro_call.expn)
         {
-            let span = format_args_inputs_span(&format_args);
+            let span = format_args_inputs_span(format_args);
             let sugg = snippet_with_applicability(cx, span, "..", &mut applicability);
             span_lint_and_sugg(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
index 12647ea1..b93d51e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_filter.rs
@@ -126,15 +126,15 @@
 ///
 /// How this is done:
 /// 1. we know that this is invoked in a method call with `filter` as the method name via `mod.rs`
-/// 2. we check that we are in a trait method. Therefore we are in an
-/// `(x as Iterator).filter({filter_arg})` method call.
+/// 2. we check that we are in a trait method. Therefore we are in an `(x as
+///    Iterator).filter({filter_arg})` method call.
 /// 3. we check that the parent expression is not a map. This is because we don't want to lint
 ///    twice, and we already have a specialized lint for that.
 /// 4. we check that the span of the filter does not contain a comment.
 /// 5. we get the type of the `Item` in the `Iterator`, and compare against the type of Option and
-///   Result.
+///    Result.
 /// 6. we finally check the contents of the filter argument to see if it is a call to `is_some` or
-///   `is_ok`.
+///    `is_ok`.
 /// 7. if all of the above are true, then we return the `FilterType`
 fn expression_type(
     cx: &LateContext<'_>,
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index 7c852a3..05e7738 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -12,8 +12,10 @@
 use rustc_span::{sym, Span};
 
 /// lint use of:
+///
 /// - `hashmap.iter().map(|(_, v)| v)`
 /// - `hashmap.into_iter().map(|(_, v)| v)`
+///
 /// on `HashMaps` and `BTreeMaps` in std
 
 pub(super) fn check<'tcx>(
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index 03b4680..5ccb524 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -12,7 +12,6 @@
 
 use super::ITER_OVEREAGER_CLONED;
 use crate::redundant_clone::REDUNDANT_CLONE;
-use crate::rustc_trait_selection::infer::TyCtxtInferExt;
 
 #[derive(Clone, Copy)]
 pub(super) enum Op<'a> {
@@ -69,16 +68,10 @@
             let mut delegate = MoveDelegate {
                 used_move: HirIdSet::default(),
             };
-            let infcx = cx.tcx.infer_ctxt().build();
 
-            ExprUseVisitor::new(
-                &mut delegate,
-                &infcx,
-                closure.body.hir_id.owner.def_id,
-                cx.param_env,
-                cx.typeck_results(),
-            )
-            .consume_body(body);
+            ExprUseVisitor::for_clippy(cx, closure.def_id, &mut delegate)
+                .consume_body(body)
+                .into_ok();
 
             let mut to_be_discarded = false;
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index 63545d6..9d67aa2 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -133,6 +133,7 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::consts::{constant, Constant};
 use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
+use clippy_utils::macros::FormatArgsStorage;
 use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
 use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty};
 pub use path_ends_with_ext::DEFAULT_ALLOWED_DOTFILES;
@@ -4087,12 +4088,14 @@
     suspicious,
     "is_empty() called on strings known at compile time"
 }
+
 pub struct Methods {
     avoid_breaking_exported_api: bool,
     msrv: Msrv,
     allow_expect_in_tests: bool,
     allow_unwrap_in_tests: bool,
     allowed_dotfiles: FxHashSet<String>,
+    format_args: FormatArgsStorage,
 }
 
 impl Methods {
@@ -4103,6 +4106,7 @@
         allow_expect_in_tests: bool,
         allow_unwrap_in_tests: bool,
         mut allowed_dotfiles: FxHashSet<String>,
+        format_args: FormatArgsStorage,
     ) -> Self {
         allowed_dotfiles.extend(DEFAULT_ALLOWED_DOTFILES.iter().map(ToString::to_string));
 
@@ -4112,6 +4116,7 @@
             allow_expect_in_tests,
             allow_unwrap_in_tests,
             allowed_dotfiles,
+            format_args,
         }
     }
 }
@@ -4281,7 +4286,15 @@
             ExprKind::MethodCall(method_call, receiver, args, _) => {
                 let method_span = method_call.ident.span;
                 or_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
-                expect_fun_call::check(cx, expr, method_span, method_call.ident.as_str(), receiver, args);
+                expect_fun_call::check(
+                    cx,
+                    &self.format_args,
+                    expr,
+                    method_span,
+                    method_call.ident.as_str(),
+                    receiver,
+                    args,
+                );
                 clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args);
                 clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args);
                 inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args);
@@ -5038,7 +5051,7 @@
 }
 
 const FN_HEADER: hir::FnHeader = hir::FnHeader {
-    unsafety: hir::Unsafety::Normal,
+    safety: hir::Safety::Safe,
     constness: hir::Constness::NotConst,
     asyncness: hir::IsAsync::NotAsync,
     abi: rustc_target::spec::abi::Abi::Rust,
@@ -5214,7 +5227,5 @@
 }
 
 fn fn_header_equals(expected: hir::FnHeader, actual: hir::FnHeader) -> bool {
-    expected.constness == actual.constness
-        && expected.unsafety == actual.unsafety
-        && expected.asyncness == actual.asyncness
+    expected.constness == actual.constness && expected.safety == actual.safety && expected.asyncness == actual.asyncness
 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 1c69565..f26f164 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -127,7 +127,7 @@
     }
 }
 
-/// checks for for collecting into a (generic) method or function argument
+/// checks for collecting into a (generic) method or function argument
 /// taking an `IntoIterator`
 fn check_collect_into_intoiterator<'tcx>(
     cx: &LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
index 520dcb2..7431dc1 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -3,10 +3,12 @@
 use clippy_utils::higher::ForLoop;
 use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::{get_iterator_item_ty, implements_trait};
-use clippy_utils::{fn_def_id, get_parent_expr};
+use clippy_utils::visitors::for_each_expr;
+use clippy_utils::{can_mut_borrow_both, fn_def_id, get_parent_expr, path_to_local};
+use core::ops::ControlFlow;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Expr, ExprKind};
+use rustc_hir::{BindingMode, Expr, ExprKind, Node, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::{sym, Symbol};
 
@@ -40,6 +42,53 @@
         && !clone_or_copy_needed
         && let Some(receiver_snippet) = snippet_opt(cx, receiver.span)
     {
+        // Issue 12098
+        // https://github.com/rust-lang/rust-clippy/issues/12098
+        // if the assignee have `mut borrow` conflict with the iteratee
+        // the lint should not execute, former didn't consider the mut case
+
+        // check whether `expr` is mutable
+        fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+            if let Some(hir_id) = path_to_local(expr)
+                && let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
+            {
+                matches!(pat.kind, PatKind::Binding(BindingMode::MUT, ..))
+            } else {
+                true
+            }
+        }
+
+        fn is_caller_or_fields_change(cx: &LateContext<'_>, body: &Expr<'_>, caller: &Expr<'_>) -> bool {
+            let mut change = false;
+            if let ExprKind::Block(block, ..) = body.kind {
+                for_each_expr(block, |e| {
+                    match e.kind {
+                        ExprKind::Assign(assignee, _, _) | ExprKind::AssignOp(_, assignee, _) => {
+                            change |= !can_mut_borrow_both(cx, caller, assignee);
+                        },
+                        _ => {},
+                    }
+                    // the return value has no effect but the function need one return value
+                    ControlFlow::<()>::Continue(())
+                });
+            }
+            change
+        }
+
+        if let ExprKind::Call(_, [child, ..]) = expr.kind {
+            // filter first layer of iterator
+            let mut child = child;
+            // get inner real caller requests for clone
+            while let ExprKind::MethodCall(_, caller, _, _) = child.kind {
+                child = caller;
+            }
+            if is_mutable(cx, child) && is_caller_or_fields_change(cx, body, child) {
+                // skip lint
+                return true;
+            }
+        };
+
+        // the lint should not be executed if no violation happens
         let snippet = if let ExprKind::MethodCall(maybe_iter_method_name, collection, [], _) = receiver.kind
             && maybe_iter_method_name.ident.name == sym::iter
             && let Some(iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator)
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index d334746..ae9aa83 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -417,7 +417,7 @@
                 }
             },
             ClauseKind::Projection(projection_predicate) => {
-                if projection_predicate.projection_ty.self_ty() == input {
+                if projection_predicate.projection_term.self_ty() == input {
                     projection_predicates.push(projection_predicate);
                 }
             },
diff --git a/src/tools/clippy/clippy_lints/src/methods/utils.rs b/src/tools/clippy/clippy_lints/src/methods/utils.rs
index c50f24f..34d7b9a 100644
--- a/src/tools/clippy/clippy_lints/src/methods/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/utils.rs
@@ -120,6 +120,7 @@
 /// operations performed on `binding_hir_ids` are:
 /// * to take non-mutable references to them
 /// * to use them as non-mutable `&self` in method calls
+///
 /// If any of `binding_hir_ids` is used in any other way, then `clone_or_copy_needed` will be true
 /// when `CloneOrCopyVisitor` is done visiting.
 struct CloneOrCopyVisitor<'cx, 'tcx> {
diff --git a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
index 0842a87..934b9f4 100644
--- a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
+++ b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
@@ -76,7 +76,7 @@
             };
 
             // get the names of the generic parameters in the type
-            let type_params = &cx.tcx.generics_of(defid).params;
+            let type_params = &cx.tcx.generics_of(defid).own_params;
             let type_param_names: Vec<_> = type_params
                 .iter()
                 .filter_map(|p| match p.kind {
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index 0e13806..5306205 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -2,7 +2,7 @@
 use clippy_utils::visitors::{for_each_expr_with_closures, Descend, Visitable};
 use core::ops::ControlFlow::Continue;
 use hir::def::{DefKind, Res};
-use hir::{BlockCheckMode, ExprKind, QPath, UnOp, Unsafety};
+use hir::{BlockCheckMode, ExprKind, Safety, QPath, UnOp};
 use rustc_ast::Mutability;
 use rustc_hir as hir;
 use rustc_lint::{LateContext, LateLintPass};
@@ -133,7 +133,7 @@
                     ty::FnPtr(sig) => sig,
                     _ => return Continue(Descend::Yes),
                 };
-                if sig.unsafety() == Unsafety::Unsafe {
+                if sig.safety() == Safety::Unsafe {
                     unsafe_ops.push(("unsafe function call occurs here", expr.span));
                 }
             },
@@ -144,7 +144,7 @@
                     .type_dependent_def_id(expr.hir_id)
                     .map(|def_id| cx.tcx.fn_sig(def_id))
                 {
-                    if sig.skip_binder().unsafety() == Unsafety::Unsafe {
+                    if sig.skip_binder().safety() == Safety::Unsafe {
                         unsafe_ops.push(("unsafe method call occurs here", expr.span));
                     }
                 }
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index a24cd4f..daf166b 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -1,6 +1,6 @@
 use clippy_config::msrvs::{self, Msrv};
 use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap};
+use clippy_utils::mir::PossibleBorrowerMap;
 use clippy_utils::source::snippet_with_context;
 use clippy_utils::ty::{implements_trait, is_copy};
 use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode};
@@ -11,9 +11,8 @@
 use rustc_index::bit_set::BitSet;
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::mir::{Rvalue, StatementKind};
 use rustc_middle::ty::{
-    self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, List, ParamTy, ProjectionPredicate, Ty,
+    self, ClauseKind, EarlyBinder, FnSig, GenericArg, GenericArgKind, ParamTy, ProjectionPredicate, Ty,
 };
 use rustc_session::impl_lint_pass;
 use rustc_span::symbol::sym;
@@ -106,7 +105,6 @@
             }
             && let count = needless_borrow_count(
                 cx,
-                &mut self.possible_borrowers,
                 fn_id,
                 cx.typeck_results().node_args(hir_id),
                 i,
@@ -155,13 +153,11 @@
 /// The following constraints will be checked:
 /// * The borrowed expression meets all the generic type's constraints.
 /// * The generic type appears only once in the functions signature.
-/// * The borrowed value will not be moved if it is used later in the function.
-#[expect(clippy::too_many_arguments)]
+/// * The borrowed value is Copy itself OR not a variable (created by a function call)
 fn needless_borrow_count<'tcx>(
     cx: &LateContext<'tcx>,
-    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
     fn_id: DefId,
-    callee_args: &'tcx List<GenericArg<'tcx>>,
+    callee_args: ty::GenericArgsRef<'tcx>,
     arg_index: usize,
     param_ty: ParamTy,
     mut expr: &Expr<'tcx>,
@@ -234,9 +230,9 @@
 
         let referent_ty = cx.typeck_results().expr_ty(referent);
 
-        if !is_copy(cx, referent_ty)
-            && (referent_ty.has_significant_drop(cx.tcx, cx.param_env)
-                || !referent_used_exactly_once(cx, possible_borrowers, reference))
+        if (!is_copy(cx, referent_ty) && !referent_ty.is_ref())
+            && let ExprKind::AddrOf(_, _, inner) = reference.kind
+            && !matches!(inner.kind, ExprKind::Call(..) | ExprKind::MethodCall(..))
         {
             return false;
         }
@@ -320,11 +316,11 @@
         && (term_param_ty.index as usize) < generics.parent_count
     {
         // The inner-most self type is a type parameter from the current function.
-        let mut projection_ty = projection_predicate.projection_ty;
+        let mut projection_term = projection_predicate.projection_term;
         loop {
-            match projection_ty.self_ty().kind() {
+            match *projection_term.self_ty().kind() {
                 ty::Alias(ty::Projection, inner_projection_ty) => {
-                    projection_ty = *inner_projection_ty;
+                    projection_term = inner_projection_ty.into();
                 },
                 ty::Param(param_ty) => {
                     return (param_ty.index as usize) >= generics.parent_count;
@@ -339,37 +335,6 @@
     }
 }
 
-fn referent_used_exactly_once<'tcx>(
-    cx: &LateContext<'tcx>,
-    possible_borrowers: &mut Vec<(LocalDefId, PossibleBorrowerMap<'tcx, 'tcx>)>,
-    reference: &Expr<'tcx>,
-) -> bool {
-    if let Some(mir) = enclosing_mir(cx.tcx, reference.hir_id)
-        && let Some(local) = expr_local(cx.tcx, reference)
-        && let [location] = *local_assignments(mir, local).as_slice()
-        && let block_data = &mir.basic_blocks[location.block]
-        && let Some(statement) = block_data.statements.get(location.statement_index)
-        && let StatementKind::Assign(box (_, Rvalue::Ref(_, _, place))) = statement.kind
-        && !place.is_indirect_first_projection()
-    {
-        let body_owner_local_def_id = cx.tcx.hir().enclosing_body_owner(reference.hir_id);
-        if possible_borrowers
-            .last()
-            .map_or(true, |&(local_def_id, _)| local_def_id != body_owner_local_def_id)
-        {
-            possible_borrowers.push((body_owner_local_def_id, PossibleBorrowerMap::new(cx, mir)));
-        }
-        let possible_borrower = &mut possible_borrowers.last_mut().unwrap().1;
-        // If `only_borrowers` were used here, the `copyable_iterator::warn` test would fail. The reason is
-        // that `PossibleBorrowerVisitor::visit_terminator` considers `place.local` a possible borrower of
-        // itself. See the comment in that method for an explanation as to why.
-        possible_borrower.bounded_borrowers(&[local], &[local, place.local], place.local, location)
-            && used_exactly_once(mir, place.local).unwrap_or(false)
-    } else {
-        false
-    }
-}
-
 // Iteratively replaces `param_ty` with `new_ty` in `args`, and similarly for each resulting
 // projected type that is a type parameter. Returns `false` if replacing the types would have an
 // effect on the function signature beyond substituting `new_ty` for `param_ty`.
@@ -404,14 +369,15 @@
         // The `replaced.insert(...)` check provides some protection against infinite loops.
         if replaced.insert(param_ty.index) {
             for projection_predicate in projection_predicates {
-                if projection_predicate.projection_ty.self_ty() == param_ty.to_ty(cx.tcx)
+                if projection_predicate.projection_term.self_ty() == param_ty.to_ty(cx.tcx)
                     && let Some(term_ty) = projection_predicate.term.ty()
                     && let ty::Param(term_param_ty) = term_ty.kind()
                 {
-                    let projection = cx.tcx.mk_ty_from_kind(ty::Alias(
-                        ty::Projection,
-                        projection_predicate.projection_ty.with_self_ty(cx.tcx, new_ty),
-                    ));
+                    let projection = projection_predicate
+                        .projection_term
+                        .with_self_ty(cx.tcx, new_ty)
+                        .expect_ty(cx.tcx)
+                        .to_ty(cx.tcx);
 
                     if let Ok(projected_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, projection)
                         && args[term_param_ty.index as usize] != GenericArg::from(projected_ty)
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index 8b4a12b..b97cb45 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -178,8 +178,7 @@
 /// Given an expression, returns true if either of the following is true
 ///
 /// - The expression is a `continue` node.
-/// - The expression node is a block with the first statement being a
-/// `continue`.
+/// - The expression node is a block with the first statement being a `continue`.
 fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>) -> bool {
     match else_expr.kind {
         ast::ExprKind::Block(ref else_block, _) => is_first_block_stmt_continue(else_block, label),
diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
index 6605d1f..5a0ae1a 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -273,24 +273,16 @@
                 msg_span,
                 "unneeded late initialization",
                 |diag| {
-                    diag.tool_only_span_suggestion(
-                        local_stmt.span,
-                        "remove the local",
-                        "",
-                        Applicability::MachineApplicable,
-                    );
-
-                    diag.span_suggestion(
-                        assign.lhs_span,
-                        format!("declare `{binding_name}` here"),
-                        let_snippet,
+                    diag.multipart_suggestion(
+                        format!("move the declaration `{binding_name}` here"),
+                        vec![(local_stmt.span, String::new()), (assign.lhs_span, let_snippet)],
                         Applicability::MachineApplicable,
                     );
                 },
             );
         },
         ExprKind::If(cond, then_expr, Some(else_expr)) if !contains_let(cond) => {
-            let (applicability, suggestions) = assignment_suggestions(cx, binding_id, [then_expr, else_expr])?;
+            let (applicability, mut suggestions) = assignment_suggestions(cx, binding_id, [then_expr, else_expr])?;
 
             span_lint_and_then(
                 cx,
@@ -298,30 +290,26 @@
                 local_stmt.span,
                 "unneeded late initialization",
                 |diag| {
-                    diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability);
-
-                    diag.span_suggestion_verbose(
-                        usage.stmt.span.shrink_to_lo(),
-                        format!("declare `{binding_name}` here"),
-                        format!("{let_snippet} = "),
-                        applicability,
-                    );
-
-                    diag.multipart_suggestion("remove the assignments from the branches", suggestions, applicability);
+                    suggestions.push((local_stmt.span, String::new()));
+                    suggestions.push((usage.stmt.span.shrink_to_lo(), format!("{let_snippet} = ")));
 
                     if usage.needs_semi {
-                        diag.span_suggestion(
-                            usage.stmt.span.shrink_to_hi(),
-                            "add a semicolon after the `if` expression",
-                            ";",
-                            applicability,
-                        );
+                        suggestions.push((usage.stmt.span.shrink_to_hi(), ";".to_owned()));
                     }
+
+                    diag.multipart_suggestion(
+                        format!(
+                            "move the declaration `{binding_name}` here and remove the assignments from the branches"
+                        ),
+                        suggestions,
+                        applicability,
+                    );
                 },
             );
         },
         ExprKind::Match(_, arms, MatchSource::Normal) => {
-            let (applicability, suggestions) = assignment_suggestions(cx, binding_id, arms.iter().map(|arm| arm.body))?;
+            let (applicability, mut suggestions) =
+                assignment_suggestions(cx, binding_id, arms.iter().map(|arm| arm.body))?;
 
             span_lint_and_then(
                 cx,
@@ -329,29 +317,18 @@
                 local_stmt.span,
                 "unneeded late initialization",
                 |diag| {
-                    diag.tool_only_span_suggestion(local_stmt.span, "remove the local", String::new(), applicability);
+                    suggestions.push((local_stmt.span, String::new()));
+                    suggestions.push((usage.stmt.span.shrink_to_lo(), format!("{let_snippet} = ")));
 
-                    diag.span_suggestion_verbose(
-                        usage.stmt.span.shrink_to_lo(),
-                        format!("declare `{binding_name}` here"),
-                        format!("{let_snippet} = "),
-                        applicability,
-                    );
+                    if usage.needs_semi {
+                        suggestions.push((usage.stmt.span.shrink_to_hi(), ";".to_owned()));
+                    }
 
                     diag.multipart_suggestion(
-                        "remove the assignments from the `match` arms",
+                        format!("move the declaration `{binding_name}` here and remove the assignments from the `match` arms"),
                         suggestions,
                         applicability,
                     );
-
-                    if usage.needs_semi {
-                        diag.span_suggestion(
-                            usage.stmt.span.shrink_to_hi(),
-                            "add a semicolon after the `match` expression",
-                            ";",
-                            applicability,
-                        );
-                    }
                 },
             );
         },
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index 9e47c3a..da6ed5f 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -11,7 +11,6 @@
     PatKind,
 };
 use rustc_hir_typeck::expr_use_visitor as euv;
-use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::{self, Ty, TyCtxt, UpvarId, UpvarPath};
@@ -102,7 +101,6 @@
 fn check_closures<'tcx>(
     ctx: &mut MutablyUsedVariablesCtxt<'tcx>,
     cx: &LateContext<'tcx>,
-    infcx: &InferCtxt<'tcx>,
     checked_closures: &mut FxHashSet<LocalDefId>,
     closures: FxHashSet<LocalDefId>,
 ) {
@@ -119,7 +117,9 @@
             .associated_body()
             .map(|(_, body_id)| hir.body(body_id))
         {
-            euv::ExprUseVisitor::new(ctx, infcx, closure, cx.param_env, cx.typeck_results()).consume_body(body);
+            euv::ExprUseVisitor::for_clippy(cx, closure, &mut *ctx)
+                .consume_body(body)
+                .into_ok();
         }
     }
 }
@@ -196,8 +196,9 @@
                 async_closures: FxHashSet::default(),
                 tcx: cx.tcx,
             };
-            let infcx = cx.tcx.infer_ctxt().build();
-            euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
+            euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx)
+                .consume_body(body)
+                .into_ok();
 
             let mut checked_closures = FxHashSet::default();
 
@@ -210,13 +211,13 @@
                 }
                 ControlFlow::<()>::Continue(())
             });
-            check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures);
+            check_closures(&mut ctx, cx, &mut checked_closures, closures);
 
             if is_async {
                 while !ctx.async_closures.is_empty() {
                     let async_closures = ctx.async_closures.clone();
                     ctx.async_closures.clear();
-                    check_closures(&mut ctx, cx, &infcx, &mut checked_closures, async_closures);
+                    check_closures(&mut ctx, cx, &mut checked_closures, async_closures);
                 }
             }
             ctx.generate_mutably_used_ids_from_aliases()
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 39d374d..f2e00ce 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -13,7 +13,6 @@
     TyKind,
 };
 use rustc_hir_typeck::expr_use_visitor as euv;
-use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::{self, Ty, TypeVisitableExt};
@@ -134,8 +133,9 @@
         // function body.
         let MovedVariablesCtxt { moved_vars } = {
             let mut ctx = MovedVariablesCtxt::default();
-            let infcx = cx.tcx.infer_ctxt().build();
-            euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
+            euv::ExprUseVisitor::for_clippy(cx, fn_def_id, &mut ctx)
+                .consume_body(body)
+                .into_ok();
             ctx
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs
index 78dd1e0..b60fea3 100644
--- a/src/tools/clippy/clippy_lints/src/new_without_default.rs
+++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs
@@ -75,7 +75,7 @@
                     if let hir::ImplItemKind::Fn(ref sig, _) = impl_item.kind {
                         let name = impl_item.ident.name;
                         let id = impl_item.owner_id;
-                        if sig.header.unsafety == hir::Unsafety::Unsafe {
+                        if sig.header.safety == hir::Safety::Unsafe {
                             // can't be implemented for unsafe new
                             return;
                         }
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index f915145..87f886b 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -94,7 +94,6 @@
 
     fn check_block_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx rustc_hir::Block<'tcx>) {
         for hir_id in self.local_bindings.pop().unwrap() {
-            // FIXME(rust/#120456) - is `swap_remove` correct?
             if let Some(span) = self.underscore_bindings.swap_remove(&hir_id) {
                 span_lint_hir(
                     cx,
@@ -109,7 +108,6 @@
 
     fn check_expr(&mut self, _: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
         if let Some(def_id) = path_to_local(expr) {
-            // FIXME(rust/#120456) - is `swap_remove` correct?
             self.underscore_bindings.swap_remove(&def_id);
         }
     }
@@ -118,7 +116,11 @@
 impl NoEffect {
     fn check_no_effect(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
         if let StmtKind::Semi(expr) = stmt.kind {
-            // move `expr.span.from_expansion()` ahead
+            // Covered by rustc `path_statements` lint
+            if matches!(expr.kind, ExprKind::Path(_)) {
+                return true;
+            }
+
             if expr.span.from_expansion() {
                 return false;
             }
diff --git a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
index 435eb90..910e584 100644
--- a/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/assign_op_pattern.rs
@@ -11,7 +11,6 @@
 use rustc_lint::LateContext;
 use rustc_middle::mir::FakeReadCause;
 use rustc_middle::ty::BorrowKind;
-use rustc_trait_selection::infer::TyCtxtInferExt;
 
 use super::ASSIGN_OP_PATTERN;
 
@@ -119,15 +118,8 @@
     }
 
     let mut s = S(HirIdSet::default());
-    let infcx = cx.tcx.infer_ctxt().build();
-    let mut v = ExprUseVisitor::new(
-        &mut s,
-        &infcx,
-        cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
-        cx.param_env,
-        cx.typeck_results(),
-    );
-    v.consume_expr(e);
+    let v = ExprUseVisitor::for_clippy(cx, e.hir_id.owner.def_id, &mut s);
+    v.consume_expr(e).into_ok();
     s.0
 }
 
@@ -151,14 +143,7 @@
     }
 
     let mut s = S(HirIdSet::default());
-    let infcx = cx.tcx.infer_ctxt().build();
-    let mut v = ExprUseVisitor::new(
-        &mut s,
-        &infcx,
-        cx.tcx.hir().body_owner_def_id(cx.enclosing_body.unwrap()),
-        cx.param_env,
-        cx.typeck_results(),
-    );
-    v.consume_expr(e);
+    let v = ExprUseVisitor::for_clippy(cx, e.hir_id.owner.def_id, &mut s);
+    v.consume_expr(e).into_ok();
     s.0
 }
diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
index ea8ed28..208b20a 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -70,7 +70,7 @@
     let without_deref = symmetric_partial_eq(cx, arg_ty, other_ty).unwrap_or_default();
     let with_deref = arg_ty
         .builtin_deref(true)
-        .and_then(|tam| symmetric_partial_eq(cx, tam.ty, other_ty))
+        .and_then(|ty| symmetric_partial_eq(cx, ty, other_ty))
         .unwrap_or_default();
 
     if !with_deref.is_implemented() && !without_deref.is_implemented() {
diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
index ef51a9a..75066c1 100644
--- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
@@ -1,8 +1,14 @@
 use clippy_utils::diagnostics::span_lint;
+use clippy_utils::is_in_test;
 use clippy_utils::macros::{is_panic, root_macro_call_first_node};
 use rustc_hir::Expr;
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_session::declare_lint_pass;
+use rustc_session::impl_lint_pass;
+
+#[derive(Clone)]
+pub struct PanicUnimplemented {
+    pub allow_panic_in_tests: bool,
+}
 
 declare_clippy_lint! {
     /// ### What it does
@@ -77,7 +83,7 @@
     "usage of the `unreachable!` macro"
 }
 
-declare_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]);
+impl_lint_pass!(PanicUnimplemented => [UNIMPLEMENTED, UNREACHABLE, TODO, PANIC]);
 
 impl<'tcx> LateLintPass<'tcx> for PanicUnimplemented {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
@@ -85,7 +91,9 @@
             return;
         };
         if is_panic(cx, macro_call.def_id) {
-            if cx.tcx.hir().is_inside_const_context(expr.hir_id) {
+            if cx.tcx.hir().is_inside_const_context(expr.hir_id)
+                || self.allow_panic_in_tests && is_in_test(cx.tcx, expr.hir_id)
+            {
                 return;
             }
 
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 2534e3c..65929cd 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -12,7 +12,7 @@
 use rustc_hir::intravisit::{walk_expr, Visitor};
 use rustc_hir::{
     self as hir, AnonConst, BinOpKind, BindingMode, Body, Expr, ExprKind, FnRetTy, FnSig, GenericArg, ImplItemKind,
-    ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, TraitFn, TraitItem, TraitItemKind, TyKind, Unsafety,
+    ItemKind, Lifetime, Mutability, Node, Param, PatKind, QPath, Safety, TraitFn, TraitItem, TraitItemKind, TyKind,
 };
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_infer::traits::{Obligation, ObligationCause};
@@ -542,7 +542,7 @@
         if let Some(args) = args
             && !args.is_empty()
             && body.map_or(true, |body| {
-                sig.header.unsafety == Unsafety::Unsafe || contains_unsafe_block(cx, body.value)
+                sig.header.safety == Safety::Unsafe || contains_unsafe_block(cx, body.value)
             })
         {
             span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index 2863eb1..47d3ed0 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -1,4 +1,3 @@
-use crate::rustc_lint::LintContext;
 use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir};
 use clippy_utils::get_parent_expr;
 use clippy_utils::sugg::Sugg;
@@ -9,7 +8,7 @@
 use rustc_hir::{
     intravisit as hir_visit, ClosureKind, CoroutineDesugaring, CoroutineKind, CoroutineSource, ExprKind, Node,
 };
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty;
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
index 6540626..63237c6 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
@@ -1,9 +1,8 @@
-use crate::rustc_lint::LintContext;
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_context;
 use rustc_errors::Applicability;
 use rustc_hir::{Block, ExprKind};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_session::declare_lint_pass;
 use rustc_span::{ExpnKind, MacroKind, Span};
 
diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
index 18fbbdb..acf44a9 100644
--- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs
@@ -201,8 +201,8 @@
 
                 if segments.is_empty() {
                     // keep track of `use {some_module, some_other_module};` usages
-                    if let UseTreeKind::Nested(trees) = &use_tree.kind {
-                        for tree in trees {
+                    if let UseTreeKind::Nested { items, .. } = &use_tree.kind {
+                        for tree in items {
                             let segments = &tree.0.prefix.segments;
                             if segments.len() == 1 {
                                 if let UseTreeKind::Simple(None) = tree.0.kind {
@@ -229,8 +229,8 @@
                         }
 
                         // nested case such as `use self::{module1::Struct1, module2::Struct2}`
-                        if let UseTreeKind::Nested(trees) = &use_tree.kind {
-                            for tree in trees {
+                        if let UseTreeKind::Nested { items, .. } = &use_tree.kind {
+                            for tree in items {
                                 let segments = &tree.0.prefix.segments;
                                 if !segments.is_empty() {
                                     imports_reused_with_self.push(segments[0].ident.name);
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 87a3c38..2921241 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -389,6 +389,10 @@
 
 impl<'tcx> LateLintPass<'tcx> for StrToString {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
+        if expr.span.from_expansion() {
+            return;
+        }
+
         if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
             && path.ident.name == sym::to_string
             && let ty = cx.typeck_results().expr_ty(self_arg)
@@ -437,6 +441,10 @@
 
 impl<'tcx> LateLintPass<'tcx> for StringToString {
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'_>) {
+        if expr.span.from_expansion() {
+            return;
+        }
+
         if let ExprKind::MethodCall(path, self_arg, ..) = &expr.kind
             && path.ident.name == sym::to_string
             && let ty = cx.typeck_results().expr_ty(self_arg)
diff --git a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
index c44f515..1dfc9f7 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/eager_transmute.rs
@@ -87,7 +87,7 @@
         && is_normalizable(cx, cx.param_env, from_ty)
         && is_normalizable(cx, cx.param_env, to_ty)
         // we only want to lint if the target type has a niche that is larger than the one of the source type
-        // e.g. `u8` to `NonZeroU8` should lint, but `NonZeroU8` to `u8` should not
+        // e.g. `u8` to `NonZero<u8>` should lint, but `NonZero<u8>` to `u8` should not
         && let Ok(from_layout) = cx.tcx.layout_of(cx.param_env.and(from_ty))
         && let Ok(to_layout) = cx.tcx.layout_of(cx.param_env.and(to_ty))
         && match (from_layout.largest_niche, to_layout.largest_niche) {
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index 7fa536a..598032c 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -257,7 +257,7 @@
 
 declare_clippy_lint! {
     /// ### What it does
-    /// Checks for transmutes from integers to `NonZero*` types, and suggests their `new_unchecked`
+    /// Checks for transmutes from `T` to `NonZero<T>`, and suggests the `new_unchecked`
     /// method instead.
     ///
     /// ### Why is this bad?
@@ -266,13 +266,13 @@
     ///
     /// ### Example
     /// ```no_run
-    /// # use core::num::NonZeroU32;
-    /// let _non_zero: NonZeroU32 = unsafe { std::mem::transmute(123) };
+    /// # use core::num::NonZero;
+    /// let _: NonZero<u32> = unsafe { std::mem::transmute(123) };
     /// ```
     /// Use instead:
     /// ```no_run
-    /// # use core::num::NonZeroU32;
-    /// let _non_zero = unsafe { NonZeroU32::new_unchecked(123) };
+    /// # use core::num::NonZero;
+    /// let _: NonZero<u32> = unsafe { NonZero::new_unchecked(123) };
     /// ```
     #[clippy::version = "1.69.0"]
     pub TRANSMUTE_INT_TO_NON_ZERO,
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
index 2bea3be..3729dfd 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_int_to_non_zero.rs
@@ -26,45 +26,22 @@
         return false;
     };
 
-    // FIXME: This can be simplified once `NonZero<T>` is stable.
-    let coercible_types = [
-        ("NonZeroU8", tcx.types.u8),
-        ("NonZeroU16", tcx.types.u16),
-        ("NonZeroU32", tcx.types.u32),
-        ("NonZeroU64", tcx.types.u64),
-        ("NonZeroU128", tcx.types.u128),
-        ("NonZeroUsize", tcx.types.usize),
-        ("NonZeroI8", tcx.types.i8),
-        ("NonZeroI16", tcx.types.i16),
-        ("NonZeroI32", tcx.types.i32),
-        ("NonZeroI64", tcx.types.i64),
-        ("NonZeroI128", tcx.types.i128),
-        ("NonZeroIsize", tcx.types.isize),
-    ];
-
-    let int_type = substs.type_at(0);
-
-    let Some(nonzero_alias) = coercible_types.iter().find_map(|(nonzero_alias, t)| {
-        if *t == int_type && *t == from_ty {
-            Some(nonzero_alias)
-        } else {
-            None
-        }
-    }) else {
+    let int_ty = substs.type_at(0);
+    if from_ty != int_ty {
         return false;
-    };
+    }
 
     span_lint_and_then(
         cx,
         TRANSMUTE_INT_TO_NON_ZERO,
         e.span,
-        format!("transmute from a `{from_ty}` to a `{nonzero_alias}`"),
+        format!("transmute from a `{from_ty}` to a `{}<{int_ty}>`", sym::NonZero),
         |diag| {
             let arg = sugg::Sugg::hir(cx, arg, "..");
             diag.span_suggestion(
                 e.span,
                 "consider using",
-                format!("{nonzero_alias}::{}({arg})", sym::new_unchecked),
+                format!("{}::{}({arg})", sym::NonZero, sym::new_unchecked),
                 Applicability::Unspecified,
             );
         },
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index cbd1618..4120bb1 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -200,7 +200,7 @@
         let item_has_safety_comment = item_has_safety_comment(cx, item);
         match (&item.kind, item_has_safety_comment) {
             // lint unsafe impl without safety comment
-            (ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.unsafety == hir::Unsafety::Unsafe => {
+            (ItemKind::Impl(impl_), HasSafetyComment::No) if impl_.safety == hir::Safety::Unsafe => {
                 if !is_lint_allowed(cx, UNDOCUMENTED_UNSAFE_BLOCKS, item.hir_id())
                     && !is_unsafe_from_proc_macro(cx, item.span)
                 {
@@ -222,7 +222,7 @@
                 }
             },
             // lint safe impl with unnecessary safety comment
-            (ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.unsafety == hir::Unsafety::Normal => {
+            (ItemKind::Impl(impl_), HasSafetyComment::Yes(pos)) if impl_.safety == hir::Safety::Safe => {
                 if !is_lint_allowed(cx, UNNECESSARY_SAFETY_COMMENT, item.hir_id()) {
                     let (span, help_span) = mk_spans(pos);
 
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index 214b69d..f0d1458 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -66,7 +66,7 @@
             let projection_pred = cx
                 .tcx
                 .instantiate_bound_regions_with_erased(proj_pred.kind().rebind(pred));
-            if projection_pred.projection_ty.args == trait_pred.trait_ref.args {
+            if projection_pred.projection_term.args == trait_pred.trait_ref.args {
                 return Some(projection_pred);
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
index ddee06b..528a1df 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
@@ -36,8 +36,8 @@
 impl EarlyLintPass for UnnecessarySelfImports {
     fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
         if let ItemKind::Use(use_tree) = &item.kind
-            && let UseTreeKind::Nested(nodes) = &use_tree.kind
-            && let [(self_tree, _)] = &**nodes
+            && let UseTreeKind::Nested { items, .. } = &use_tree.kind
+            && let [(self_tree, _)] = &**items
             && let [self_seg] = &*self_tree.prefix.segments
             && self_seg.ident.name == kw::SelfLower
             && let Some(last_segment) = use_tree.prefix.segments.last()
diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
index 51b3ea9..309eaed 100644
--- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
+++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
@@ -49,8 +49,8 @@
             unsafe_to_safe_check(old_name, new_name, cx, span);
         },
         UseTreeKind::Simple(None) | UseTreeKind::Glob => {},
-        UseTreeKind::Nested(ref nested_use_tree) => {
-            for (use_tree, _) in nested_use_tree {
+        UseTreeKind::Nested { ref items, .. } => {
+            for (use_tree, _) in items {
                 check_use_tree(use_tree, cx, span);
             }
         },
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 2622abd..c0d9bcd 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -6,7 +6,6 @@
 use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, Visitor};
 use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, HirId, Node, PathSegment, UnOp};
 use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceWithHirId};
-use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::lint::in_external_macro;
@@ -252,16 +251,9 @@
                 local_id: unwrap_info.local_id,
             };
 
-            let infcx = self.cx.tcx.infer_ctxt().build();
-            let mut vis = ExprUseVisitor::new(
-                &mut delegate,
-                &infcx,
-                cond.hir_id.owner.def_id,
-                self.cx.param_env,
-                self.cx.typeck_results(),
-            );
-            vis.walk_expr(cond);
-            vis.walk_expr(branch);
+            let vis = ExprUseVisitor::for_clippy(self.cx, cond.hir_id.owner.def_id, &mut delegate);
+            vis.walk_expr(cond).into_ok();
+            vis.walk_expr(branch).into_ok();
 
             if delegate.is_mutated {
                 // if the variable is mutated, we don't know whether it can be unwrapped.
diff --git a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs
index 58e66c9..5acfd35 100644
--- a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs
@@ -1,4 +1,4 @@
-use clippy_utils::macros::AST_FORMAT_ARGS;
+use clippy_utils::macros::FormatArgsStorage;
 use clippy_utils::source::snippet_opt;
 use itertools::Itertools;
 use rustc_ast::{Crate, Expr, ExprKind, FormatArgs};
@@ -9,13 +9,20 @@
 use rustc_span::{hygiene, Span};
 use std::iter::once;
 use std::mem;
-use std::rc::Rc;
 
-/// Collects [`rustc_ast::FormatArgs`] so that future late passes can call
-/// [`clippy_utils::macros::find_format_args`]
-#[derive(Default)]
+/// Populates [`FormatArgsStorage`] with AST [`FormatArgs`] nodes
 pub struct FormatArgsCollector {
-    format_args: FxHashMap<Span, Rc<FormatArgs>>,
+    format_args: FxHashMap<Span, FormatArgs>,
+    storage: FormatArgsStorage,
+}
+
+impl FormatArgsCollector {
+    pub fn new(storage: FormatArgsStorage) -> Self {
+        Self {
+            format_args: FxHashMap::default(),
+            storage,
+        }
+    }
 }
 
 impl_lint_pass!(FormatArgsCollector => []);
@@ -27,16 +34,12 @@
                 return;
             }
 
-            self.format_args
-                .insert(expr.span.with_parent(None), Rc::new((**args).clone()));
+            self.format_args.insert(expr.span.with_parent(None), (**args).clone());
         }
     }
 
     fn check_crate_post(&mut self, _: &EarlyContext<'_>, _: &Crate) {
-        AST_FORMAT_ARGS.with(|ast_format_args| {
-            let result = ast_format_args.set(mem::take(&mut self.format_args));
-            debug_assert!(result.is_ok());
-        });
+        self.storage.set(mem::take(&mut self.format_args));
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 26c6859..ff6ee0d 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -1,5 +1,5 @@
 use clippy_utils::diagnostics::{span_lint, span_lint_and_then};
-use clippy_utils::macros::{find_format_args, format_arg_removal_span, root_macro_call_first_node, MacroCall};
+use clippy_utils::macros::{format_arg_removal_span, root_macro_call_first_node, FormatArgsStorage, MacroCall};
 use clippy_utils::source::{expand_past_previous_comma, snippet_opt};
 use clippy_utils::{is_in_cfg_test, is_in_test_function};
 use rustc_ast::token::LitKind;
@@ -236,13 +236,15 @@
 
 #[derive(Default)]
 pub struct Write {
+    format_args: FormatArgsStorage,
     in_debug_impl: bool,
     allow_print_in_tests: bool,
 }
 
 impl Write {
-    pub fn new(allow_print_in_tests: bool) -> Self {
+    pub fn new(format_args: FormatArgsStorage, allow_print_in_tests: bool) -> Self {
         Self {
+            format_args,
             allow_print_in_tests,
             ..Default::default()
         }
@@ -307,7 +309,7 @@
             _ => return,
         }
 
-        if let Some(format_args) = find_format_args(cx, expr, macro_call.expn) {
+        if let Some(format_args) = self.format_args.get(cx, expr, macro_call.expn) {
             // ignore `writeln!(w)` and `write!(v, some_macro!())`
             if format_args.span.from_expansion() {
                 return;
@@ -315,15 +317,15 @@
 
             match diag_name {
                 sym::print_macro | sym::eprint_macro | sym::write_macro => {
-                    check_newline(cx, &format_args, &macro_call, name);
+                    check_newline(cx, format_args, &macro_call, name);
                 },
                 sym::println_macro | sym::eprintln_macro | sym::writeln_macro => {
-                    check_empty_string(cx, &format_args, &macro_call, name);
+                    check_empty_string(cx, format_args, &macro_call, name);
                 },
                 _ => {},
             }
 
-            check_literal(cx, &format_args, name);
+            check_literal(cx, format_args, name);
 
             if !self.in_debug_impl {
                 for piece in &format_args.template {
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 529d201..d4a5f54 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -386,21 +386,21 @@
         (
             Trait(box ast::Trait {
                 is_auto: la,
-                unsafety: lu,
+                safety: lu,
                 generics: lg,
                 bounds: lb,
                 items: li,
             }),
             Trait(box ast::Trait {
                 is_auto: ra,
-                unsafety: ru,
+                safety: ru,
                 generics: rg,
                 bounds: rb,
                 items: ri,
             }),
         ) => {
             la == ra
-                && matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
+                && matches!(lu, Safety::Default) == matches!(ru, Safety::Default)
                 && eq_generics(lg, rg)
                 && over(lb, rb, eq_generic_bound)
                 && over(li, ri, |l, r| eq_item(l, r, eq_assoc_item_kind))
@@ -408,7 +408,7 @@
         (TraitAlias(lg, lb), TraitAlias(rg, rb)) => eq_generics(lg, rg) && over(lb, rb, eq_generic_bound),
         (
             Impl(box ast::Impl {
-                unsafety: lu,
+                safety: lu,
                 polarity: lp,
                 defaultness: ld,
                 constness: lc,
@@ -418,7 +418,7 @@
                 items: li,
             }),
             Impl(box ast::Impl {
-                unsafety: ru,
+                safety: ru,
                 polarity: rp,
                 defaultness: rd,
                 constness: rc,
@@ -428,7 +428,7 @@
                 items: ri,
             }),
         ) => {
-            matches!(lu, Unsafe::No) == matches!(ru, Unsafe::No)
+            matches!(lu, Safety::Default) == matches!(ru, Safety::Default)
                 && matches!(lp, ImplPolarity::Positive) == matches!(rp, ImplPolarity::Positive)
                 && eq_defaultness(*ld, *rd)
                 && matches!(lc, ast::Const::No) == matches!(rc, ast::Const::No)
@@ -605,7 +605,7 @@
 }
 
 pub fn eq_fn_header(l: &FnHeader, r: &FnHeader) -> bool {
-    matches!(l.unsafety, Unsafe::No) == matches!(r.unsafety, Unsafe::No)
+    matches!(l.safety, Safety::Default) == matches!(r.safety, Safety::Default)
         && eq_opt_coroutine_kind(l.coroutine_kind, r.coroutine_kind)
         && matches!(l.constness, Const::No) == matches!(r.constness, Const::No)
         && eq_ext(&l.ext, &r.ext)
@@ -648,7 +648,7 @@
     match (l, r) {
         (Glob, Glob) => true,
         (Simple(l), Simple(r)) => both(l, r, |l, r| eq_id(*l, *r)),
-        (Nested(l), Nested(r)) => over(l, r, |(l, _), (r, _)| eq_use_tree(l, r)),
+        (Nested { items: l, .. }, Nested { items: r, .. }) => over(l, r, |(l, _), (r, _)| eq_use_tree(l, r)),
         _ => false,
     }
 }
@@ -712,7 +712,7 @@
             both(ll, rl, |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
         },
         (BareFn(l), BareFn(r)) => {
-            l.unsafety == r.unsafety
+            l.safety == r.safety
                 && eq_ext(&l.ext, &r.ext)
                 && over(&l.generic_params, &r.generic_params, eq_generic_param)
                 && eq_fn_decl(&l.decl, &r.decl)
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 4226731..553e899 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -18,8 +18,8 @@
 use rustc_hir::intravisit::FnKind;
 use rustc_hir::{
     Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl,
-    ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem,
-    TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource,
+    ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, Safety, TraitItem,
+    TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Variant, VariantData, YieldSource,
 };
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty::TyCtxt;
@@ -207,10 +207,9 @@
         ItemKind::Struct(VariantData::Struct { .. }, _) => (Pat::Str("struct"), Pat::Str("}")),
         ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")),
         ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")),
-        ItemKind::Trait(_, Unsafety::Unsafe, ..)
+        ItemKind::Trait(_, Safety::Unsafe, ..)
         | ItemKind::Impl(Impl {
-            unsafety: Unsafety::Unsafe,
-            ..
+            safety: Safety::Unsafe, ..
         }) => (Pat::Str("unsafe"), Pat::Str("}")),
         ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")),
         ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")),
@@ -323,7 +322,7 @@
         TyKind::Ptr(MutTy { ty, .. }) => (Pat::Str("*"), ty_search_pat(ty).1),
         TyKind::Ref(_, MutTy { ty, .. }) => (Pat::Str("&"), ty_search_pat(ty).1),
         TyKind::BareFn(bare_fn) => (
-            if bare_fn.unsafety == Unsafety::Unsafe {
+            if bare_fn.safety == Safety::Unsafe {
                 Pat::Str("unsafe")
             } else if bare_fn.abi != Abi::Rust {
                 Pat::Str("extern")
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index c921168..9f28562 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1082,7 +1082,7 @@
                 mut_ty.mutbl.hash(&mut self.s);
             },
             TyKind::BareFn(bfn) => {
-                bfn.unsafety.hash(&mut self.s);
+                bfn.safety.hash(&mut self.s);
                 bfn.abi.hash(&mut self.s);
                 for arg in bfn.decl.inputs {
                     self.hash_ty(arg);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index a49414a..4c603bd 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -7,6 +7,7 @@
 #![feature(never_type)]
 #![feature(rustc_private)]
 #![feature(assert_matches)]
+#![feature(unwrap_infallible)]
 #![recursion_limit = "512"]
 #![cfg_attr(feature = "deny-warnings", deny(warnings))]
 #![allow(
@@ -192,6 +193,21 @@
     None
 }
 
+/// Checks if the given local has an initializer or is from something other than a `let` statement
+///
+/// e.g. returns true for `x` in `fn f(x: usize) { .. }` and `let x = 1;` but false for `let x;`
+pub fn local_is_initialized(cx: &LateContext<'_>, local: HirId) -> bool {
+    for (_, node) in cx.tcx.hir().parent_iter(local) {
+        match node {
+            Node::Pat(..) | Node::PatField(..) => {},
+            Node::LetStmt(let_stmt) => return let_stmt.init.is_some(),
+            _ => return true,
+        }
+    }
+
+    false
+}
+
 /// Returns `true` if the given `NodeId` is inside a constant context
 ///
 /// # Example
@@ -1498,15 +1514,18 @@
 }
 
 /// Checks whether the given `Expr` is a range equivalent to a `RangeFull`.
+///
 /// For the lower bound, this means that:
 /// - either there is none
 /// - or it is the smallest value that can be represented by the range's integer type
+///
 /// For the upper bound, this means that:
 /// - either there is none
 /// - or it is the largest value that can be represented by the range's integer type and is
 ///   inclusive
 /// - or it is a call to some container's `len` method and is exclusive, and the range is passed to
 ///   a method call on that same container (e.g. `v.drain(..v.len())`)
+///
 /// If the given `Expr` is not some kind of range, the function returns `false`.
 pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Option<&Path<'_>>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr);
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index 257dd76..8daab9b 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -5,15 +5,13 @@
 use arrayvec::ArrayVec;
 use rustc_ast::{FormatArgs, FormatArgument, FormatPlaceholder};
 use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::{Lrc, OnceLock};
 use rustc_hir::{self as hir, Expr, ExprKind, HirId, Node, QPath};
 use rustc_lint::LateContext;
 use rustc_span::def_id::DefId;
 use rustc_span::hygiene::{self, MacroKind, SyntaxContext};
 use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Span, SpanData, Symbol};
-use std::cell::OnceCell;
 use std::ops::ControlFlow;
-use std::rc::Rc;
-use std::sync::atomic::{AtomicBool, Ordering};
 
 const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[
     sym::assert_eq_macro,
@@ -388,50 +386,44 @@
     }
 }
 
-thread_local! {
-    /// We preserve the [`FormatArgs`] structs from the early pass for use in the late pass to be
-    /// able to access the many features of a [`LateContext`].
+/// Stores AST [`FormatArgs`] nodes for use in late lint passes, as they are in a desugared form in
+/// the HIR
+#[derive(Default, Clone)]
+pub struct FormatArgsStorage(Lrc<OnceLock<FxHashMap<Span, FormatArgs>>>);
+
+impl FormatArgsStorage {
+    /// Returns an AST [`FormatArgs`] node if a `format_args` expansion is found as a descendant of
+    /// `expn_id`
     ///
-    /// A thread local is used because [`FormatArgs`] is `!Send` and `!Sync`, we are making an
-    /// assumption that the early pass that populates the map and the later late passes will all be
-    /// running on the same thread.
-    #[doc(hidden)]
-    pub static AST_FORMAT_ARGS: OnceCell<FxHashMap<Span, Rc<FormatArgs>>> = {
-        static CALLED: AtomicBool = AtomicBool::new(false);
-        debug_assert!(
-            !CALLED.swap(true, Ordering::SeqCst),
-            "incorrect assumption: `AST_FORMAT_ARGS` should only be accessed by a single thread",
-        );
-
-        OnceCell::new()
-    };
-}
-
-/// Returns an AST [`FormatArgs`] node if a `format_args` expansion is found as a descendant of
-/// `expn_id`
-pub fn find_format_args(cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) -> Option<Rc<FormatArgs>> {
-    let format_args_expr = for_each_expr(start, |expr| {
-        let ctxt = expr.span.ctxt();
-        if ctxt.outer_expn().is_descendant_of(expn_id) {
-            if macro_backtrace(expr.span)
-                .map(|macro_call| cx.tcx.item_name(macro_call.def_id))
-                .any(|name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))
-            {
-                ControlFlow::Break(expr)
+    /// See also [`find_format_arg_expr`]
+    pub fn get(&self, cx: &LateContext<'_>, start: &Expr<'_>, expn_id: ExpnId) -> Option<&FormatArgs> {
+        let format_args_expr = for_each_expr(start, |expr| {
+            let ctxt = expr.span.ctxt();
+            if ctxt.outer_expn().is_descendant_of(expn_id) {
+                if macro_backtrace(expr.span)
+                    .map(|macro_call| cx.tcx.item_name(macro_call.def_id))
+                    .any(|name| matches!(name, sym::const_format_args | sym::format_args | sym::format_args_nl))
+                {
+                    ControlFlow::Break(expr)
+                } else {
+                    ControlFlow::Continue(Descend::Yes)
+                }
             } else {
-                ControlFlow::Continue(Descend::Yes)
+                ControlFlow::Continue(Descend::No)
             }
-        } else {
-            ControlFlow::Continue(Descend::No)
-        }
-    })?;
+        })?;
 
-    AST_FORMAT_ARGS.with(|ast_format_args| {
-        ast_format_args
-            .get()?
-            .get(&format_args_expr.span.with_parent(None))
-            .cloned()
-    })
+        debug_assert!(self.0.get().is_some(), "`FormatArgsStorage` not yet populated");
+
+        self.0.get()?.get(&format_args_expr.span.with_parent(None))
+    }
+
+    /// Should only be called by `FormatArgsCollector`
+    pub fn set(&self, format_args: FxHashMap<Span, FormatArgs>) {
+        self.0
+            .set(format_args)
+            .expect("`FormatArgsStorage::set` should only be called once");
+    }
 }
 
 /// Attempt to find the [`rustc_hir::Expr`] that corresponds to the [`FormatArgument`]'s value, if
diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
index 06229ac..7b4fd8a 100644
--- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
+++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs
@@ -149,7 +149,7 @@
 }
 
 fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) {
-    use rustc_middle::mir::Rvalue::{Aggregate, BinaryOp, Cast, CheckedBinaryOp, Repeat, UnaryOp, Use};
+    use rustc_middle::mir::Rvalue::{Aggregate, BinaryOp, Cast, Repeat, UnaryOp, Use};
 
     let mut visit_op = |op: &mir::Operand<'_>| match op {
         mir::Operand::Copy(p) | mir::Operand::Move(p) => visit(p.local),
@@ -159,7 +159,7 @@
     match rvalue {
         Use(op) | Repeat(op, _) | Cast(_, op, _) | UnaryOp(_, op) => visit_op(op),
         Aggregate(_, ops) => ops.iter().for_each(visit_op),
-        BinaryOp(_, box (lhs, rhs)) | CheckedBinaryOp(_, box (lhs, rhs)) => {
+        BinaryOp(_, box (lhs, rhs)) => {
             visit_op(lhs);
             visit_op(rhs);
         },
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 325c9be..8ee7d87 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -3,7 +3,7 @@
 // of terminologies might not be relevant in the context of Clippy. Note that its behavior might
 // differ from the time of `rustc` even if the name stays the same.
 
-use clippy_config::msrvs::Msrv;
+use clippy_config::msrvs::{self, Msrv};
 use hir::LangItem;
 use rustc_attr::StableSince;
 use rustc_const_eval::transform::check_consts::ConstCx;
@@ -42,7 +42,7 @@
     for bb in &*body.basic_blocks {
         check_terminator(tcx, body, bb.terminator(), msrv)?;
         for stmt in &bb.statements {
-            check_statement(tcx, body, def_id, stmt)?;
+            check_statement(tcx, body, def_id, stmt, msrv)?;
         }
     }
     Ok(())
@@ -102,13 +102,14 @@
     def_id: DefId,
     rvalue: &Rvalue<'tcx>,
     span: Span,
+    msrv: &Msrv,
 ) -> McfResult {
     match rvalue {
         Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())),
         Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
-            check_place(tcx, *place, span, body)
+            check_place(tcx, *place, span, body, msrv)
         },
-        Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body),
+        Rvalue::CopyForDeref(place) => check_place(tcx, *place, span, body, msrv),
         Rvalue::Repeat(operand, _)
         | Rvalue::Use(operand)
         | Rvalue::Cast(
@@ -122,7 +123,7 @@
             | CastKind::PointerCoercion(PointerCoercion::MutToConstPointer | PointerCoercion::ArrayToPointer),
             operand,
             _,
-        ) => check_operand(tcx, operand, span, body),
+        ) => check_operand(tcx, operand, span, body, msrv),
         Rvalue::Cast(
             CastKind::PointerCoercion(
                 PointerCoercion::UnsafeFnPointer
@@ -133,15 +134,13 @@
             _,
         ) => Err((span, "function pointer casts are not allowed in const fn".into())),
         Rvalue::Cast(CastKind::PointerCoercion(PointerCoercion::Unsize), op, cast_ty) => {
-            let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) {
-                deref_ty.ty
-            } else {
+            let Some(pointee_ty) = cast_ty.builtin_deref(true) else {
                 // We cannot allow this for now.
                 return Err((span, "unsizing casts are only allowed for references right now".into()));
             };
             let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id));
             if let ty::Slice(_) | ty::Str = unsized_ty.kind() {
-                check_operand(tcx, op, span, body)?;
+                check_operand(tcx, op, span, body, msrv)?;
                 // Casting/coercing things to slices is fine.
                 Ok(())
             } else {
@@ -161,9 +160,9 @@
             "transmute can attempt to turn pointers into integers, so is unstable in const fn".into(),
         )),
         // binops are fine on integers
-        Rvalue::BinaryOp(_, box (lhs, rhs)) | Rvalue::CheckedBinaryOp(_, box (lhs, rhs)) => {
-            check_operand(tcx, lhs, span, body)?;
-            check_operand(tcx, rhs, span, body)?;
+        Rvalue::BinaryOp(_, box (lhs, rhs)) => {
+            check_operand(tcx, lhs, span, body, msrv)?;
+            check_operand(tcx, rhs, span, body, msrv)?;
             let ty = lhs.ty(body, tcx);
             if ty.is_integral() || ty.is_bool() || ty.is_char() {
                 Ok(())
@@ -179,14 +178,14 @@
         Rvalue::UnaryOp(_, operand) => {
             let ty = operand.ty(body, tcx);
             if ty.is_integral() || ty.is_bool() {
-                check_operand(tcx, operand, span, body)
+                check_operand(tcx, operand, span, body, msrv)
             } else {
                 Err((span, "only int and `bool` operations are stable in const fn".into()))
             }
         },
         Rvalue::Aggregate(_, operands) => {
             for operand in operands {
-                check_operand(tcx, operand, span, body)?;
+                check_operand(tcx, operand, span, body, msrv)?;
             }
             Ok(())
         },
@@ -198,28 +197,29 @@
     body: &Body<'tcx>,
     def_id: DefId,
     statement: &Statement<'tcx>,
+    msrv: &Msrv,
 ) -> McfResult {
     let span = statement.source_info.span;
     match &statement.kind {
         StatementKind::Assign(box (place, rval)) => {
-            check_place(tcx, *place, span, body)?;
-            check_rvalue(tcx, body, def_id, rval, span)
+            check_place(tcx, *place, span, body, msrv)?;
+            check_rvalue(tcx, body, def_id, rval, span, msrv)
         },
 
-        StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body),
+        StatementKind::FakeRead(box (_, place)) => check_place(tcx, *place, span, body, msrv),
         // just an assignment
         StatementKind::SetDiscriminant { place, .. } | StatementKind::Deinit(place) => {
-            check_place(tcx, **place, span, body)
+            check_place(tcx, **place, span, body, msrv)
         },
 
-        StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body),
+        StatementKind::Intrinsic(box NonDivergingIntrinsic::Assume(op)) => check_operand(tcx, op, span, body, msrv),
 
         StatementKind::Intrinsic(box NonDivergingIntrinsic::CopyNonOverlapping(
             rustc_middle::mir::CopyNonOverlapping { dst, src, count },
         )) => {
-            check_operand(tcx, dst, span, body)?;
-            check_operand(tcx, src, span, body)?;
-            check_operand(tcx, count, span, body)
+            check_operand(tcx, dst, span, body, msrv)?;
+            check_operand(tcx, src, span, body, msrv)?;
+            check_operand(tcx, count, span, body, msrv)
         },
         // These are all NOPs
         StatementKind::StorageLive(_)
@@ -233,7 +233,13 @@
     }
 }
 
-fn check_operand<'tcx>(tcx: TyCtxt<'tcx>, operand: &Operand<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
+fn check_operand<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    operand: &Operand<'tcx>,
+    span: Span,
+    body: &Body<'tcx>,
+    msrv: &Msrv,
+) -> McfResult {
     match operand {
         Operand::Move(place) => {
             if !place.projection.as_ref().is_empty()
@@ -245,9 +251,9 @@
                 ));
             }
 
-            check_place(tcx, *place, span, body)
+            check_place(tcx, *place, span, body, msrv)
         },
-        Operand::Copy(place) => check_place(tcx, *place, span, body),
+        Operand::Copy(place) => check_place(tcx, *place, span, body, msrv),
         Operand::Constant(c) => match c.check_static_ptr(tcx) {
             Some(_) => Err((span, "cannot access `static` items in const fn".into())),
             None => Ok(()),
@@ -255,23 +261,27 @@
     }
 }
 
-fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>) -> McfResult {
+fn check_place<'tcx>(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'tcx>, msrv: &Msrv) -> McfResult {
     for (base, elem) in place.as_ref().iter_projections() {
         match elem {
             ProjectionElem::Field(..) => {
-                let base_ty = base.ty(body, tcx).ty;
-                if let Some(def) = base_ty.ty_adt_def() {
-                    // No union field accesses in `const fn`
-                    if def.is_union() {
-                        return Err((span, "accessing union fields is unstable".into()));
-                    }
+                if base.ty(body, tcx).ty.is_union() && !msrv.meets(msrvs::CONST_FN_UNION) {
+                    return Err((span, "accessing union fields is unstable".into()));
                 }
             },
+            ProjectionElem::Deref => match base.ty(body, tcx).ty.kind() {
+                ty::RawPtr(_, hir::Mutability::Mut) => {
+                    return Err((span, "dereferencing raw mut pointer in const fn is unstable".into()));
+                },
+                ty::RawPtr(_, hir::Mutability::Not) if !msrv.meets(msrvs::CONST_RAW_PTR_DEREF) => {
+                    return Err((span, "dereferencing raw const pointer in const fn is unstable".into()));
+                },
+                _ => (),
+            },
             ProjectionElem::ConstantIndex { .. }
             | ProjectionElem::OpaqueCast(..)
             | ProjectionElem::Downcast(..)
             | ProjectionElem::Subslice { .. }
-            | ProjectionElem::Deref
             | ProjectionElem::Subtype(_)
             | ProjectionElem::Index(_) => {},
         }
@@ -304,7 +314,7 @@
             }
             Ok(())
         },
-        TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),
+        TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body, msrv),
         TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => {
             Err((span, "const fn coroutines are unstable".into()))
         },
@@ -341,10 +351,10 @@
                     ));
                 }
 
-                check_operand(tcx, func, span, body)?;
+                check_operand(tcx, func, span, body, msrv)?;
 
                 for arg in args {
-                    check_operand(tcx, &arg.node, span, body)?;
+                    check_operand(tcx, &arg.node, span, body, msrv)?;
                 }
                 Ok(())
             } else {
@@ -357,7 +367,7 @@
             msg: _,
             target: _,
             unwind: _,
-        } => check_operand(tcx, cond, span, body),
+        } => check_operand(tcx, cond, span, body, msrv),
         TerminatorKind::InlineAsm { .. } => Err((span, "cannot use inline assembly in const fn".into())),
     }
 }
@@ -402,7 +412,7 @@
             tcx,
             ObligationCause::dummy_with_span(body.span),
             ConstCx::new(tcx, body).param_env,
-            TraitRef::from_lang_item(tcx, LangItem::Destruct, body.span, [ty]),
+            TraitRef::new(tcx, tcx.require_lang_item(LangItem::Destruct, Some(body.span)), [ty]),
         );
 
         let infcx = tcx.infer_ctxt().build();
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index e72467e..fd67e03 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -250,7 +250,7 @@
 /// - Applicability level `Unspecified` will never be changed.
 /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`.
 /// - If the default value is used and the applicability level is `MachineApplicable`, change it to
-/// `HasPlaceholders`
+///   `HasPlaceholders`
 pub fn snippet_with_applicability<'a, T: LintContext>(
     cx: &T,
     span: Span,
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 8d60572..6319c7b 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -11,7 +11,6 @@
 use rustc_hir as hir;
 use rustc_hir::{Closure, ExprKind, HirId, MutTy, TyKind};
 use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, PlaceBase, PlaceWithHirId};
-use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::{EarlyContext, LateContext, LintContext};
 use rustc_middle::hir::place::ProjectionKind;
 use rustc_middle::mir::{FakeReadCause, Mutability};
@@ -68,8 +67,7 @@
     /// - Applicability level `Unspecified` will never be changed.
     /// - If the span is inside a macro, change the applicability level to `MaybeIncorrect`.
     /// - If the default value is used and the applicability level is `MachineApplicable`, change it
-    ///   to
-    /// `HasPlaceholders`
+    ///   to `HasPlaceholders`
     pub fn hir_with_applicability(
         cx: &LateContext<'_>,
         expr: &hir::Expr<'_>,
@@ -831,8 +829,9 @@
             applicability: Applicability::MachineApplicable,
         };
 
-        let infcx = cx.tcx.infer_ctxt().build();
-        ExprUseVisitor::new(&mut visitor, &infcx, def_id, cx.param_env, cx.typeck_results()).consume_body(closure_body);
+        ExprUseVisitor::for_clippy(cx, def_id, &mut visitor)
+            .consume_body(closure_body)
+            .into_ok();
 
         if !visitor.suggestion_start.is_empty() {
             return Some(DerefClosure {
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 23750ed..2dacc34 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -9,8 +9,7 @@
 use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Expr, FnDecl, LangItem, TyKind, Unsafety};
-use rustc_infer::infer::type_variable::TypeVariableOrigin;
+use rustc_hir::{Expr, FnDecl, Safety, LangItem, TyKind};
 use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::mir::interpret::Scalar;
@@ -19,7 +18,7 @@
 use rustc_middle::ty::layout::ValidityRequirement;
 use rustc_middle::ty::{
     self, AdtDef, AliasTy, AssocKind, Binder, BoundRegion, FnSig, GenericArg, GenericArgKind, GenericArgsRef,
-    GenericParamDefKind, IntTy, List, ParamEnv, Region, RegionKind, ToPredicate, TraitRef, Ty, TyCtxt,
+    GenericParamDefKind, IntTy, ParamEnv, Region, RegionKind, Upcast, TraitRef, Ty, TyCtxt,
     TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, UintTy, VariantDef, VariantDiscr,
 };
 use rustc_span::symbol::Ident;
@@ -274,15 +273,7 @@
     let infcx = tcx.infer_ctxt().build();
     let args = args
         .into_iter()
-        .map(|arg| {
-            arg.into().unwrap_or_else(|| {
-                let orig = TypeVariableOrigin {
-                    span: DUMMY_SP,
-                    param_def_id: None,
-                };
-                infcx.next_ty_var(orig).into()
-            })
-        })
+        .map(|arg| arg.into().unwrap_or_else(|| infcx.next_ty_var(DUMMY_SP).into()))
         .collect::<Vec<_>>();
 
     // If an effect arg was not specified, we need to specify it.
@@ -316,7 +307,7 @@
         cause: ObligationCause::dummy(),
         param_env,
         recursion_depth: 0,
-        predicate: Binder::dummy(trait_ref).to_predicate(tcx),
+        predicate: trait_ref.upcast(tcx),
     };
     infcx
         .evaluate_obligation(&obligation)
@@ -567,7 +558,7 @@
 /// Returns `true` if the given type is an `unsafe` function.
 pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     match ty.kind() {
-        ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).unsafety() == Unsafety::Unsafe,
+        ty::FnDef(..) | ty::FnPtr(_) => ty.fn_sig(cx.tcx).safety() == Safety::Unsafe,
         _ => false,
     }
 }
@@ -800,7 +791,8 @@
                 inputs = Some(i);
             },
             ty::ClauseKind::Projection(p)
-                if Some(p.projection_ty.def_id) == lang_items.fn_once_output() && p.projection_ty.self_ty() == ty =>
+                if Some(p.projection_term.def_id) == lang_items.fn_once_output()
+                    && p.projection_term.self_ty() == ty =>
             {
                 if output.is_some() {
                     // Multiple different fn trait impls. Is this even allowed?
@@ -839,7 +831,7 @@
                 }
                 inputs = Some(i);
             },
-            ty::ClauseKind::Projection(p) if Some(p.projection_ty.def_id) == lang_items.fn_once_output() => {
+            ty::ClauseKind::Projection(p) if Some(p.projection_term.def_id) == lang_items.fn_once_output() => {
                 if output.is_some() {
                     // Multiple different fn trait impls. Is this even allowed?
                     return None;
@@ -961,7 +953,7 @@
 
 impl AdtVariantInfo {
     /// Returns ADT variants ordered by size
-    pub fn new<'tcx>(cx: &LateContext<'tcx>, adt: AdtDef<'tcx>, subst: &'tcx List<GenericArg<'tcx>>) -> Vec<Self> {
+    pub fn new<'tcx>(cx: &LateContext<'tcx>, adt: AdtDef<'tcx>, subst: GenericArgsRef<'tcx>) -> Vec<Self> {
         let mut variants_size = adt
             .variants()
             .iter()
@@ -1070,11 +1062,11 @@
 fn assert_generic_args_match<'tcx>(tcx: TyCtxt<'tcx>, did: DefId, args: &[GenericArg<'tcx>]) {
     let g = tcx.generics_of(did);
     let parent = g.parent.map(|did| tcx.generics_of(did));
-    let count = g.parent_count + g.params.len();
+    let count = g.parent_count + g.own_params.len();
     let params = parent
-        .map_or([].as_slice(), |p| p.params.as_slice())
+        .map_or([].as_slice(), |p| p.own_params.as_slice())
         .iter()
-        .chain(&g.params)
+        .chain(&g.own_params)
         .map(|x| &x.kind);
 
     assert!(
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index 2241494..8021930 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -176,7 +176,7 @@
             .get(*lang_item)
             .map_or(Certainty::Uncertain, |def_id| {
                 let generics = cx.tcx.generics_of(def_id);
-                if generics.parent_count == 0 && generics.params.is_empty() {
+                if generics.is_empty() {
                     Certainty::Certain(if resolves_to_type { Some(def_id) } else { None })
                 } else {
                     Certainty::Uncertain
@@ -206,7 +206,7 @@
             // Checking `res_generics_def_id(..)` before calling `generics_of` avoids an ICE.
             if cx.tcx.res_generics_def_id(path_segment.res).is_some() {
                 let generics = cx.tcx.generics_of(def_id);
-                let count = generics.params.len() - usize::from(generics.host_effect_index.is_some());
+                let count = generics.own_params.len() - usize::from(generics.host_effect_index.is_some());
                 let lhs = if (parent_certainty.is_certain() || generics.parent_count == 0) && count == 0 {
                     Certainty::Certain(None)
                 } else {
@@ -299,7 +299,7 @@
     let fn_sig = cx.tcx.fn_sig(callee_def_id).skip_binder();
 
     // Check that all type parameters appear in the functions input types.
-    (0..(generics.parent_count + generics.params.len()) as u32).all(|index| {
+    (0..(generics.parent_count + generics.own_params.len()) as u32).all(|index| {
         Some(index as usize) == generics.host_effect_index
             || fn_sig
                 .inputs()
diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs
index a145920..2a25d51 100644
--- a/src/tools/clippy/clippy_utils/src/usage.rs
+++ b/src/tools/clippy/clippy_utils/src/usage.rs
@@ -5,7 +5,6 @@
 use rustc_hir::intravisit::{self, Visitor};
 use rustc_hir::{self as hir, Expr, ExprKind, HirId, HirIdSet};
 use rustc_hir_typeck::expr_use_visitor::{Delegate, ExprUseVisitor, Place, PlaceBase, PlaceWithHirId};
-use rustc_infer::infer::TyCtxtInferExt;
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::mir::FakeReadCause;
@@ -17,15 +16,9 @@
         used_mutably: HirIdSet::default(),
         skip: false,
     };
-    let infcx = cx.tcx.infer_ctxt().build();
-    ExprUseVisitor::new(
-        &mut delegate,
-        &infcx,
-        expr.hir_id.owner.def_id,
-        cx.param_env,
-        cx.typeck_results(),
-    )
-    .walk_expr(expr);
+    ExprUseVisitor::for_clippy(cx, expr.hir_id.owner.def_id, &mut delegate)
+        .walk_expr(expr)
+        .into_ok();
 
     if delegate.skip {
         return None;
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index a3f3b32..90b5629 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -6,7 +6,7 @@
 use rustc_hir::intravisit::{self, walk_block, walk_expr, Visitor};
 use rustc_hir::{
     AnonConst, Arm, Block, BlockCheckMode, Body, BodyId, Expr, ExprKind, HirId, ItemId, ItemKind, LetExpr, Pat, QPath,
-    Stmt, UnOp, UnsafeSource, Unsafety,
+    Safety, Stmt, UnOp, UnsafeSource,
 };
 use rustc_lint::LateContext;
 use rustc_middle::hir::nested_filter;
@@ -421,16 +421,16 @@
                         .typeck_results()
                         .type_dependent_def_id(e.hir_id)
                         .map_or(false, |id| {
-                            self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe
+                            self.cx.tcx.fn_sig(id).skip_binder().safety() == Safety::Unsafe
                         }) =>
                 {
                     self.is_unsafe = true;
                 },
                 ExprKind::Call(func, _) => match *self.cx.typeck_results().expr_ty(func).peel_refs().kind() {
-                    ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().unsafety() == Unsafety::Unsafe => {
+                    ty::FnDef(id, _) if self.cx.tcx.fn_sig(id).skip_binder().safety() == Safety::Unsafe => {
                         self.is_unsafe = true;
                     },
-                    ty::FnPtr(sig) if sig.unsafety() == Unsafety::Unsafe => self.is_unsafe = true,
+                    ty::FnPtr(sig) if sig.safety() == Safety::Unsafe => self.is_unsafe = true,
                     _ => walk_expr(self, e),
                 },
                 ExprKind::Path(ref p)
@@ -452,7 +452,7 @@
         }
         fn visit_nested_item(&mut self, id: ItemId) {
             if let ItemKind::Impl(i) = &self.cx.tcx.hir().item(id).kind {
-                self.is_unsafe = i.unsafety == Unsafety::Unsafe;
+                self.is_unsafe = i.safety == Safety::Unsafe;
             }
         }
     }
diff --git a/src/tools/clippy/lintcheck/Cargo.toml b/src/tools/clippy/lintcheck/Cargo.toml
index a828d12..8c5a409 100644
--- a/src/tools/clippy/lintcheck/Cargo.toml
+++ b/src/tools/clippy/lintcheck/Cargo.toml
@@ -13,7 +13,7 @@
 [dependencies]
 anyhow = "1.0.69"
 cargo_metadata = "0.15.3"
-clap = { version = "4.1.8", features = ["derive", "env"] }
+clap = { version = "4.4", features = ["derive", "env"] }
 crates_io_api = "0.8.1"
 crossbeam-channel = "0.5.6"
 flate2 = "1.0"
diff --git a/src/tools/clippy/lintcheck/src/config.rs b/src/tools/clippy/lintcheck/src/config.rs
index e678d40..3f712f4 100644
--- a/src/tools/clippy/lintcheck/src/config.rs
+++ b/src/tools/clippy/lintcheck/src/config.rs
@@ -1,5 +1,5 @@
 use clap::Parser;
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 use std::path::PathBuf;
 
 #[derive(Clone, Debug, Parser)]
@@ -61,7 +61,7 @@
             config.max_jobs = if config.fix || config.recursive {
                 1
             } else {
-                std::thread::available_parallelism().map_or(1, NonZeroUsize::get)
+                std::thread::available_parallelism().map_or(1, NonZero::get)
             };
         };
 
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 055f305..a0585ff 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
 [toolchain]
-channel = "nightly-2024-05-02"
+channel = "nightly-2024-05-16"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr
index 103e60d..9177e99 100644
--- a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr
+++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.stderr
@@ -42,4 +42,32 @@
 19 | pedantic = { level = "warn", priority = -2 }
    |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-error: could not compile `fail` (lib) due to 3 previous errors
+error: lint group `rust_2018_idioms` has the same priority (0) as a lint
+  --> Cargo.toml:23:1
+   |
+23 | rust_2018_idioms = "warn"
+   | ^^^^^^^^^^^^^^^^   ------ has an implicit priority of 0
+24 | bare_trait_objects = "allow"
+   | ------------------ has the same priority as this lint
+   |
+   = note: the order of the lints in the table is ignored by Cargo
+help: to have lints override the group set `rust_2018_idioms` to a lower priority
+   |
+23 | rust_2018_idioms = { level = "warn", priority = -1 }
+   |                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: lint group `pedantic` has the same priority (0) as a lint
+  --> Cargo.toml:27:1
+   |
+27 | pedantic = "warn"
+   | ^^^^^^^^   ------ has an implicit priority of 0
+28 | similar_names = "allow"
+   | ------------- has the same priority as this lint
+   |
+   = note: the order of the lints in the table is ignored by Cargo
+help: to have lints override the group set `pedantic` to a lower priority
+   |
+27 | pedantic = { level = "warn", priority = -1 }
+   |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error: could not compile `fail` (lib) due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml
index 4ce41f7..e4d4af9 100644
--- a/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml
+++ b/src/tools/clippy/tests/ui-cargo/lint_groups_priority/fail/Cargo.toml
@@ -18,3 +18,11 @@
 [lints.clippy]
 pedantic = { level = "warn", priority = -1 }
 similar_names = { level = "allow", priority = -1 }
+
+[workspace.lints.rust]
+rust_2018_idioms = "warn"
+bare_trait_objects = "allow"
+
+[workspace.lints.clippy]
+pedantic = "warn"
+similar_names = "allow"
diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs
new file mode 100644
index 0000000..f5e01b4
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.rs
@@ -0,0 +1,260 @@
+//! Tests macro_metavars_in_unsafe with default configuration
+#![feature(decl_macro, lint_reasons)]
+#![warn(clippy::macro_metavars_in_unsafe)]
+#![allow(clippy::no_effect)]
+
+#[macro_export]
+macro_rules! allow_works {
+    ($v:expr) => {
+        #[expect(clippy::macro_metavars_in_unsafe)]
+        unsafe {
+            $v;
+        };
+    };
+}
+
+#[macro_export]
+macro_rules! simple {
+    ($v:expr) => {
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            dbg!($v);
+        }
+    };
+}
+
+#[macro_export]
+#[rustfmt::skip] // for some reason rustfmt rewrites $r#unsafe to r#u$nsafe, bug?
+macro_rules! raw_symbol {
+    ($r#mod:expr, $r#unsafe:expr) => {
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            $r#mod;
+        }
+        $r#unsafe;
+    };
+}
+
+#[macro_export]
+macro_rules! multilevel_unsafe {
+    ($v:expr) => {
+        unsafe {
+            unsafe {
+                //~^ ERROR: this macro expands metavariables in an unsafe block
+                $v;
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! in_function {
+    ($v:expr) => {
+        unsafe {
+            fn f() {
+                // function introduces a new body, so don't lint.
+                $v;
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! in_function_with_unsafe {
+    ($v:expr) => {
+        unsafe {
+            fn f() {
+                unsafe {
+                    //~^ ERROR: this macro expands metavariables in an unsafe block
+                    $v;
+                }
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! const_static {
+    ($c:expr, $s:expr) => {
+        unsafe {
+            // const and static introduces new body, don't lint
+            const _X: i32 = $c;
+            static _Y: i32 = $s;
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! const_generic_in_struct {
+    ($inside_unsafe:expr, $outside_unsafe:expr) => {
+        unsafe {
+            struct Ty<
+                const L: i32 = 1,
+                const M: i32 = {
+                    1;
+                    unsafe { $inside_unsafe }
+                    //~^ ERROR: this macro expands metavariables in an unsafe block
+                },
+                const N: i32 = { $outside_unsafe },
+            >;
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! fn_with_const_generic {
+    ($inside_unsafe:expr, $outside_unsafe:expr) => {
+        unsafe {
+            fn f<const N: usize>() {
+                $outside_unsafe;
+                unsafe {
+                    //~^ ERROR: this macro expands metavariables in an unsafe block
+                    $inside_unsafe;
+                }
+            }
+        }
+    };
+}
+
+#[macro_export]
+macro_rules! variables {
+    ($inside_unsafe:expr, $outside_unsafe:expr) => {
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            $inside_unsafe;
+            let inside_unsafe = 1;
+            inside_unsafe;
+        }
+        $outside_unsafe;
+        let outside_unsafe = 1;
+        outside_unsafe;
+    };
+}
+
+#[macro_export]
+macro_rules! multiple_matchers {
+    ($inside_unsafe:expr, $outside_unsafe:expr) => {
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            $inside_unsafe;
+        }
+        $outside_unsafe;
+    };
+    ($($v:expr, $x:expr),+) => {
+        $(
+            $v;
+            unsafe {
+                //~^ ERROR: this macro expands metavariables in an unsafe block
+                $x;
+            }
+        );+
+    };
+}
+
+#[macro_export]
+macro_rules! multiple_unsafe_blocks {
+    ($w:expr, $x:expr, $y:expr) => {
+        $w;
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            $x;
+        }
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            $x;
+            $y;
+        }
+    };
+}
+
+pub macro macro2_0($v:expr) {
+    unsafe {
+        //~^ ERROR: this macro expands metavariables in an unsafe block
+        $v;
+    }
+}
+
+// don't lint private macros with the default configuration
+macro_rules! private_mac {
+    ($v:expr) => {
+        unsafe {
+            $v;
+        }
+    };
+}
+
+// don't lint exported macros that are doc(hidden) because they also aren't part of the public API
+#[macro_export]
+#[doc(hidden)]
+macro_rules! exported_but_hidden {
+    ($v:expr) => {
+        unsafe {
+            $v;
+        }
+    };
+}
+
+// don't lint if the same metavariable is expanded in an unsafe block and then outside of one:
+// unsafe {} is still needed at callsite so not problematic
+#[macro_export]
+macro_rules! does_require_unsafe {
+    ($v:expr) => {
+        unsafe {
+            $v;
+        }
+        $v;
+    };
+}
+
+#[macro_export]
+macro_rules! unsafe_from_root_ctxt {
+    ($v:expr) => {
+        // Expands to unsafe { 1 }, but the unsafe block is from the root ctxt and not this macro,
+        // so no warning.
+        $v;
+    };
+}
+
+// invoked from another macro, should still generate a warning
+#[macro_export]
+macro_rules! nested_macro_helper {
+    ($v:expr) => {{
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            $v;
+        }
+    }};
+}
+
+#[macro_export]
+macro_rules! nested_macros {
+    ($v:expr, $v2:expr) => {{
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            nested_macro_helper!($v);
+            $v;
+        }
+    }};
+}
+
+fn main() {
+    allow_works!(1);
+    simple!(1);
+    raw_symbol!(1, 1);
+    multilevel_unsafe!(1);
+    in_function!(1);
+    in_function_with_unsafe!(1);
+    const_static!(1, 1);
+    const_generic_in_struct!(1, 1);
+    fn_with_const_generic!(1, 1);
+    variables!(1, 1);
+    multiple_matchers!(1, 1);
+    multiple_matchers!(1, 1, 1, 1);
+    macro2_0!(1);
+    private_mac!(1);
+    exported_but_hidden!(1);
+    does_require_unsafe!(1);
+    multiple_unsafe_blocks!(1, 1, 1);
+    unsafe_from_root_ctxt!(unsafe { 1 });
+    nested_macros!(1, 1);
+}
diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr
new file mode 100644
index 0000000..d6b97f6
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/default/test.stderr
@@ -0,0 +1,187 @@
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:19:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             dbg!($v);
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+   = note: `-D clippy::macro-metavars-in-unsafe` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::macro_metavars_in_unsafe)]`
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:30:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             $r#mod;
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:42:13
+   |
+LL | /             unsafe {
+LL | |
+LL | |                 $v;
+LL | |             }
+   | |_____________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:67:17
+   |
+LL | /                 unsafe {
+LL | |
+LL | |                     $v;
+LL | |                 }
+   | |_________________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:95:21
+   |
+LL |                     unsafe { $inside_unsafe }
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:110:17
+   |
+LL | /                 unsafe {
+LL | |
+LL | |                     $inside_unsafe;
+LL | |                 }
+   | |_________________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:122:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             $inside_unsafe;
+LL | |             let inside_unsafe = 1;
+LL | |             inside_unsafe;
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:137:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             $inside_unsafe;
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:146:13
+   |
+LL | /             unsafe {
+LL | |
+LL | |                 $x;
+LL | |             }
+   | |_____________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:171:5
+   |
+LL | /     unsafe {
+LL | |
+LL | |         $v;
+LL | |     }
+   | |_____^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:158:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             $x;
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:162:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             $x;
+LL | |             $y;
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:222:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             $v;
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/default/test.rs:232:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             nested_macro_helper!($v);
+LL | |             $v;
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+
+error: aborting due to 14 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/clippy.toml b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/clippy.toml
new file mode 100644
index 0000000..d4bbc2a
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/clippy.toml
@@ -0,0 +1 @@
+warn-unsafe-macro-metavars-in-private-macros = true
diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.rs b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.rs
new file mode 100644
index 0000000..2bbe1fa
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.rs
@@ -0,0 +1,15 @@
+//! Tests macro_metavars_in_unsafe with private (non-exported) macros
+#![warn(clippy::macro_metavars_in_unsafe)]
+
+macro_rules! mac {
+    ($v:expr) => {
+        unsafe {
+            //~^ ERROR: this macro expands metavariables in an unsafe block
+            dbg!($v);
+        }
+    };
+}
+
+fn main() {
+    mac!(1);
+}
diff --git a/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.stderr b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.stderr
new file mode 100644
index 0000000..f9c418b
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/macro_metavars_in_unsafe/private/test.stderr
@@ -0,0 +1,17 @@
+error: this macro expands metavariables in an unsafe block
+  --> tests/ui-toml/macro_metavars_in_unsafe/private/test.rs:6:9
+   |
+LL | /         unsafe {
+LL | |
+LL | |             dbg!($v);
+LL | |         }
+   | |_________^
+   |
+   = note: this allows the user of the macro to write unsafe code outside of an unsafe block
+   = help: consider expanding any metavariables outside of this block, e.g. by storing them in a variable
+   = help: ... or also expand referenced metavariables in a safe context to require an unsafe block at callsite
+   = note: `-D clippy::macro-metavars-in-unsafe` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::macro_metavars_in_unsafe)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/panic/clippy.toml b/src/tools/clippy/tests/ui-toml/panic/clippy.toml
new file mode 100644
index 0000000..5d6230d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/panic/clippy.toml
@@ -0,0 +1 @@
+allow-panic-in-tests = true
diff --git a/src/tools/clippy/tests/ui-toml/panic/panic.rs b/src/tools/clippy/tests/ui-toml/panic/panic.rs
new file mode 100644
index 0000000..618a37d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/panic/panic.rs
@@ -0,0 +1,54 @@
+//@compile-flags: --test
+#![warn(clippy::panic)]
+
+fn main() {
+    enum Enam {
+        A,
+    }
+    let a = Enam::A;
+    match a {
+        Enam::A => {},
+        _ => panic!(""),
+    }
+}
+
+#[test]
+fn lonely_test() {
+    enum Enam {
+        A,
+    }
+    let a = Enam::A;
+    match a {
+        Enam::A => {},
+        _ => panic!(""),
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    // should not lint in `#[cfg(test)]` modules
+    #[test]
+    fn test_fn() {
+        enum Enam {
+            A,
+        }
+        let a = Enam::A;
+        match a {
+            Enam::A => {},
+            _ => panic!(""),
+        }
+
+        bar();
+    }
+
+    fn bar() {
+        enum Enam {
+            A,
+        }
+        let a = Enam::A;
+        match a {
+            Enam::A => {},
+            _ => panic!(""),
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui-toml/panic/panic.stderr b/src/tools/clippy/tests/ui-toml/panic/panic.stderr
new file mode 100644
index 0000000..bf7503e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/panic/panic.stderr
@@ -0,0 +1,11 @@
+error: `panic` should not be present in production code
+  --> tests/ui-toml/panic/panic.rs:11:14
+   |
+LL |         _ => panic!(""),
+   |              ^^^^^^^^^^
+   |
+   = note: `-D clippy::panic` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::panic)]`
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/default/clippy.toml b/src/tools/clippy/tests/ui-toml/renamed_function_params/default/clippy.toml
new file mode 100644
index 0000000..5381e70
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/default/clippy.toml
@@ -0,0 +1,2 @@
+# Ignore `From`, `TryFrom`, `FromStr` by default
+# allow-renamed-params-for = []
diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/extend/clippy.toml b/src/tools/clippy/tests/ui-toml/renamed_function_params/extend/clippy.toml
new file mode 100644
index 0000000..9b3853e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/extend/clippy.toml
@@ -0,0 +1,2 @@
+# Ignore `From`, `TryFrom`, `FromStr` by default
+allow-renamed-params-for = [ "..", "std::ops::Add", "renamed_function_params::MyTrait" ]
diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.default.stderr b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.default.stderr
new file mode 100644
index 0000000..2d700f6
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.default.stderr
@@ -0,0 +1,46 @@
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:30:18
+   |
+LL |     fn eq(&self, rhs: &Self) -> bool {
+   |                  ^^^ help: consider using the default name: `other`
+   |
+   = note: `-D clippy::renamed-function-params` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::renamed_function_params)]`
+
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:34:18
+   |
+LL |     fn ne(&self, rhs: &Self) -> bool {
+   |                  ^^^ help: consider using the default name: `other`
+
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:48:19
+   |
+LL |     fn foo(&self, i_dont_wanna_use_your_name: u8) {} // only lint in `extend`
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using the default name: `val`
+
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:55:31
+   |
+LL |     fn hash<H: Hasher>(&self, states: &mut H) {
+   |                               ^^^^^^ help: consider using the default name: `state`
+
+error: renamed function parameters of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:59:30
+   |
+LL |     fn hash_slice<H: Hasher>(date: &[Self], states: &mut H) {
+   |                              ^^^^           ^^^^^^
+   |
+help: consider using the default names
+   |
+LL |     fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) {
+   |                              ~~~~           ~~~~~
+
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:80:18
+   |
+LL |     fn add(self, b: B) -> C {
+   |                  ^ help: consider using the default name: `rhs`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.extend.stderr b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.extend.stderr
new file mode 100644
index 0000000..e57554f
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.extend.stderr
@@ -0,0 +1,34 @@
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:30:18
+   |
+LL |     fn eq(&self, rhs: &Self) -> bool {
+   |                  ^^^ help: consider using the default name: `other`
+   |
+   = note: `-D clippy::renamed-function-params` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::renamed_function_params)]`
+
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:34:18
+   |
+LL |     fn ne(&self, rhs: &Self) -> bool {
+   |                  ^^^ help: consider using the default name: `other`
+
+error: renamed function parameter of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:55:31
+   |
+LL |     fn hash<H: Hasher>(&self, states: &mut H) {
+   |                               ^^^^^^ help: consider using the default name: `state`
+
+error: renamed function parameters of trait impl
+  --> tests/ui-toml/renamed_function_params/renamed_function_params.rs:59:30
+   |
+LL |     fn hash_slice<H: Hasher>(date: &[Self], states: &mut H) {
+   |                              ^^^^           ^^^^^^
+   |
+help: consider using the default names
+   |
+LL |     fn hash_slice<H: Hasher>(data: &[Self], state: &mut H) {
+   |                              ~~~~           ~~~~~
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.rs b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.rs
new file mode 100644
index 0000000..f3eb910
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/renamed_function_params/renamed_function_params.rs
@@ -0,0 +1,110 @@
+//@no-rustfix
+//@revisions: default extend
+//@[default] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/renamed_function_params/default
+//@[extend] rustc-env:CLIPPY_CONF_DIR=tests/ui-toml/renamed_function_params/extend
+#![warn(clippy::renamed_function_params)]
+#![allow(clippy::partialeq_ne_impl, clippy::to_string_trait_impl)]
+#![allow(unused)]
+
+use std::hash::{Hash, Hasher};
+
+struct A;
+impl From<A> for String {
+    fn from(_value: A) -> Self {
+        String::new()
+    }
+}
+impl ToString for A {
+    fn to_string(&self) -> String {
+        String::new()
+    }
+}
+
+struct B(u32);
+impl std::convert::From<B> for String {
+    fn from(b: B) -> Self {
+        b.0.to_string()
+    }
+}
+impl PartialEq for B {
+    fn eq(&self, rhs: &Self) -> bool {
+        //~^ ERROR: renamed function parameter of trait impl
+        self.0 == rhs.0
+    }
+    fn ne(&self, rhs: &Self) -> bool {
+        //~^ ERROR: renamed function parameter of trait impl
+        self.0 != rhs.0
+    }
+}
+
+trait MyTrait {
+    fn foo(&self, val: u8);
+    fn bar(a: u8, b: u8);
+    fn baz(self, _val: u8);
+    fn quz(&self, _: u8);
+}
+
+impl MyTrait for B {
+    fn foo(&self, i_dont_wanna_use_your_name: u8) {} // only lint in `extend`
+    fn bar(_a: u8, _: u8) {}
+    fn baz(self, val: u8) {}
+    fn quz(&self, val: u8) {}
+}
+
+impl Hash for B {
+    fn hash<H: Hasher>(&self, states: &mut H) {
+        //~^ ERROR: renamed function parameter of trait impl
+        self.0.hash(states);
+    }
+    fn hash_slice<H: Hasher>(date: &[Self], states: &mut H) {
+        //~^ ERROR: renamed function parameters of trait impl
+        for d in date {
+            d.hash(states);
+        }
+    }
+}
+
+impl B {
+    fn totally_irrelevant(&self, right: bool) {}
+    fn some_fn(&self, other: impl MyTrait) {}
+}
+
+#[derive(Copy, Clone)]
+enum C {
+    A,
+    B(u32),
+}
+
+impl std::ops::Add<B> for C {
+    type Output = C;
+    fn add(self, b: B) -> C {
+        // only lint in `extend`
+        C::B(b.0)
+    }
+}
+
+impl From<A> for C {
+    fn from(_: A) -> C {
+        C::A
+    }
+}
+
+trait CustomTraitA {
+    fn foo(&self, other: u32);
+}
+trait CustomTraitB {
+    fn bar(&self, value: u8);
+}
+
+macro_rules! impl_trait {
+    ($impl_for:ident, $tr:ty, $fn_name:ident, $t:ty) => {
+        impl $tr for $impl_for {
+            fn $fn_name(&self, v: $t) {}
+        }
+    };
+}
+
+impl_trait!(C, CustomTraitA, foo, u32);
+impl_trait!(C, CustomTraitB, bar, u8);
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs
index 7f28efd..f02bd07 100644
--- a/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs
+++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_types/conf_disallowed_types.rs
@@ -40,3 +40,9 @@
     let _ = HashMap;
     let _: usize = 64_usize;
 }
+
+mod useless_attribute {
+    // Regression test for https://github.com/rust-lang/rust-clippy/issues/12753
+    #[allow(clippy::disallowed_types)]
+    use std::collections::HashMap;
+}
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 722e9b3..5cf9c0f 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -8,8 +8,10 @@
            allow-expect-in-tests
            allow-mixed-uninlined-format-args
            allow-one-hash-in-raw-strings
+           allow-panic-in-tests
            allow-print-in-tests
            allow-private-module-inception
+           allow-renamed-params-for
            allow-unwrap-in-tests
            allow-useless-vec-in-tests
            allowed-dotfiles
@@ -74,6 +76,7 @@
            vec-box-size-threshold
            verbose-bit-mask-threshold
            warn-on-all-wildcard-imports
+           warn-unsafe-macro-metavars-in-private-macros
   --> $DIR/tests/ui-toml/toml_unknown_key/clippy.toml:2:1
    |
 LL | foobar = 42
@@ -89,8 +92,10 @@
            allow-expect-in-tests
            allow-mixed-uninlined-format-args
            allow-one-hash-in-raw-strings
+           allow-panic-in-tests
            allow-print-in-tests
            allow-private-module-inception
+           allow-renamed-params-for
            allow-unwrap-in-tests
            allow-useless-vec-in-tests
            allowed-dotfiles
@@ -155,6 +160,7 @@
            vec-box-size-threshold
            verbose-bit-mask-threshold
            warn-on-all-wildcard-imports
+           warn-unsafe-macro-metavars-in-private-macros
   --> $DIR/tests/ui-toml/toml_unknown_key/clippy.toml:4:1
    |
 LL | barfoo = 53
@@ -170,8 +176,10 @@
            allow-expect-in-tests
            allow-mixed-uninlined-format-args
            allow-one-hash-in-raw-strings
+           allow-panic-in-tests
            allow-print-in-tests
            allow-private-module-inception
+           allow-renamed-params-for
            allow-unwrap-in-tests
            allow-useless-vec-in-tests
            allowed-dotfiles
@@ -236,6 +244,7 @@
            vec-box-size-threshold
            verbose-bit-mask-threshold
            warn-on-all-wildcard-imports
+           warn-unsafe-macro-metavars-in-private-macros
   --> $DIR/tests/ui-toml/toml_unknown_key/clippy.toml:7:1
    |
 LL | allow_mixed_uninlined_format_args = true
diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
index 66d71f3..33a91e8 100644
--- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
+++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs
@@ -15,7 +15,7 @@
 
 extern crate proc_macro_derive;
 
-use core::num::{NonZeroUsize, Saturating, Wrapping};
+use core::num::{NonZero, Saturating, Wrapping};
 
 const ONE: i32 = 1;
 const ZERO: i32 = 0;
@@ -494,15 +494,15 @@
 }
 
 pub fn issue_11392() {
-    fn example_div(unsigned: usize, nonzero_unsigned: NonZeroUsize) -> usize {
+    fn example_div(unsigned: usize, nonzero_unsigned: NonZero<usize>) -> usize {
         unsigned / nonzero_unsigned
     }
 
-    fn example_rem(unsigned: usize, nonzero_unsigned: NonZeroUsize) -> usize {
+    fn example_rem(unsigned: usize, nonzero_unsigned: NonZero<usize>) -> usize {
         unsigned % nonzero_unsigned
     }
 
-    let (unsigned, nonzero_unsigned) = (0, NonZeroUsize::new(1).unwrap());
+    let (unsigned, nonzero_unsigned) = (0, NonZero::new(1).unwrap());
     example_div(unsigned, nonzero_unsigned);
     example_rem(unsigned, nonzero_unsigned);
 }
diff --git a/src/tools/clippy/tests/ui/assigning_clones.fixed b/src/tools/clippy/tests/ui/assigning_clones.fixed
index 8387c7d..70ab43b 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.fixed
+++ b/src/tools/clippy/tests/ui/assigning_clones.fixed
@@ -62,6 +62,16 @@
     mut_thing.clone_from(ref_thing + ref_thing);
 }
 
+fn clone_method_macro() {
+    let mut s = String::from("");
+    s.clone_from(&format!("{} {}", "hello", "world"));
+}
+
+fn clone_function_macro() {
+    let mut s = String::from("");
+    Clone::clone_from(&mut s, &format!("{} {}", "hello", "world"));
+}
+
 fn assign_to_init_mut_var(b: HasCloneFrom) -> HasCloneFrom {
     let mut a = HasCloneFrom;
     for _ in 1..10 {
@@ -86,6 +96,12 @@
     a = b.clone();
 }
 
+fn late_init_let_tuple() {
+    let (p, q): (String, String);
+    p = "ghi".to_string();
+    q = p.clone();
+}
+
 #[derive(Clone)]
 pub struct HasDeriveClone;
 
@@ -208,6 +224,16 @@
     ToOwned::clone_into(ref_str, &mut mut_thing);
 }
 
+fn owned_method_macro() {
+    let mut s = String::from("");
+    format!("{} {}", "hello", "world").clone_into(&mut s);
+}
+
+fn owned_function_macro() {
+    let mut s = String::from("");
+    ToOwned::clone_into(&format!("{} {}", "hello", "world"), &mut s);
+}
+
 struct FakeToOwned;
 impl FakeToOwned {
     /// This looks just like `ToOwned::to_owned`
diff --git a/src/tools/clippy/tests/ui/assigning_clones.rs b/src/tools/clippy/tests/ui/assigning_clones.rs
index 6f4da9f..9699fed 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.rs
+++ b/src/tools/clippy/tests/ui/assigning_clones.rs
@@ -62,6 +62,16 @@
     *mut_thing = (ref_thing + ref_thing).clone();
 }
 
+fn clone_method_macro() {
+    let mut s = String::from("");
+    s = format!("{} {}", "hello", "world").clone();
+}
+
+fn clone_function_macro() {
+    let mut s = String::from("");
+    s = Clone::clone(&format!("{} {}", "hello", "world"));
+}
+
 fn assign_to_init_mut_var(b: HasCloneFrom) -> HasCloneFrom {
     let mut a = HasCloneFrom;
     for _ in 1..10 {
@@ -86,6 +96,12 @@
     a = b.clone();
 }
 
+fn late_init_let_tuple() {
+    let (p, q): (String, String);
+    p = "ghi".to_string();
+    q = p.clone();
+}
+
 #[derive(Clone)]
 pub struct HasDeriveClone;
 
@@ -208,6 +224,16 @@
     mut_thing = ToOwned::to_owned(ref_str);
 }
 
+fn owned_method_macro() {
+    let mut s = String::from("");
+    s = format!("{} {}", "hello", "world").to_owned();
+}
+
+fn owned_function_macro() {
+    let mut s = String::from("");
+    s = ToOwned::to_owned(&format!("{} {}", "hello", "world"));
+}
+
 struct FakeToOwned;
 impl FakeToOwned {
     /// This looks just like `ToOwned::to_owned`
diff --git a/src/tools/clippy/tests/ui/assigning_clones.stderr b/src/tools/clippy/tests/ui/assigning_clones.stderr
index 793927b..a685163 100644
--- a/src/tools/clippy/tests/ui/assigning_clones.stderr
+++ b/src/tools/clippy/tests/ui/assigning_clones.stderr
@@ -62,64 +62,88 @@
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `mut_thing.clone_from(ref_thing + ref_thing)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:68:9
+  --> tests/ui/assigning_clones.rs:67:5
+   |
+LL |     s = format!("{} {}", "hello", "world").clone();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `s.clone_from(&format!("{} {}", "hello", "world"))`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:72:5
+   |
+LL |     s = Clone::clone(&format!("{} {}", "hello", "world"));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_from()`: `Clone::clone_from(&mut s, &format!("{} {}", "hello", "world"))`
+
+error: assigning the result of `Clone::clone()` may be inefficient
+  --> tests/ui/assigning_clones.rs:78:9
    |
 LL |         a = b.clone();
    |         ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:133:5
+  --> tests/ui/assigning_clones.rs:149:5
    |
 LL |     a = b.clone();
    |     ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
 
 error: assigning the result of `Clone::clone()` may be inefficient
-  --> tests/ui/assigning_clones.rs:140:5
+  --> tests/ui/assigning_clones.rs:156:5
    |
 LL |     a = b.clone();
    |     ^^^^^^^^^^^^^ help: use `clone_from()`: `a.clone_from(&b)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:141:5
+  --> tests/ui/assigning_clones.rs:157:5
    |
 LL |     a = c.to_owned();
    |     ^^^^^^^^^^^^^^^^ help: use `clone_into()`: `c.clone_into(&mut a)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:171:5
+  --> tests/ui/assigning_clones.rs:187:5
    |
 LL |     *mut_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(mut_string)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:175:5
+  --> tests/ui/assigning_clones.rs:191:5
    |
 LL |     mut_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut mut_string)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:196:5
+  --> tests/ui/assigning_clones.rs:212:5
    |
 LL |     **mut_box_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:200:5
+  --> tests/ui/assigning_clones.rs:216:5
    |
 LL |     **mut_box_string = ref_str.to_owned();
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ref_str.clone_into(&mut (*mut_box_string))`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:204:5
+  --> tests/ui/assigning_clones.rs:220:5
    |
 LL |     *mut_thing = ToOwned::to_owned(ref_str);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, mut_thing)`
 
 error: assigning the result of `ToOwned::to_owned()` may be inefficient
-  --> tests/ui/assigning_clones.rs:208:5
+  --> tests/ui/assigning_clones.rs:224:5
    |
 LL |     mut_thing = ToOwned::to_owned(ref_str);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(ref_str, &mut mut_thing)`
 
-error: aborting due to 20 previous errors
+error: assigning the result of `ToOwned::to_owned()` may be inefficient
+  --> tests/ui/assigning_clones.rs:229:5
+   |
+LL |     s = format!("{} {}", "hello", "world").to_owned();
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `format!("{} {}", "hello", "world").clone_into(&mut s)`
+
+error: assigning the result of `ToOwned::to_owned()` may be inefficient
+  --> tests/ui/assigning_clones.rs:234:5
+   |
+LL |     s = ToOwned::to_owned(&format!("{} {}", "hello", "world"));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `clone_into()`: `ToOwned::clone_into(&format!("{} {}", "hello", "world"), &mut s)`
+
+error: aborting due to 24 previous errors
 
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed
new file mode 100644
index 0000000..9877991
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.fixed
@@ -0,0 +1,47 @@
+#![warn(clippy::doc_lazy_continuation)]
+
+/// > blockquote with
+/// > lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn first() {}
+
+/// > blockquote with no
+/// > lazy continuation
+fn first_nowarn() {}
+
+/// > blockquote with no
+///
+/// lazy continuation
+fn two_nowarn() {}
+
+/// > nest here
+/// >
+/// > > nest here
+/// > > lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn two() {}
+
+/// > nest here
+/// >
+/// > > nest here
+/// > > lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn three() {}
+
+/// >   * > nest here
+/// >     > lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn four() {}
+
+/// > * > nest here
+/// >   > lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn four_point_1() {}
+
+/// * > nest here lazy continuation
+fn five() {}
+
+/// 1. > nest here
+///    > lazy continuation (this results in strange indentation, but still works)
+//~^ ERROR: doc quote missing `>` marker
+fn six() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs
new file mode 100644
index 0000000..587b2fd
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.rs
@@ -0,0 +1,47 @@
+#![warn(clippy::doc_lazy_continuation)]
+
+/// > blockquote with
+/// lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn first() {}
+
+/// > blockquote with no
+/// > lazy continuation
+fn first_nowarn() {}
+
+/// > blockquote with no
+///
+/// lazy continuation
+fn two_nowarn() {}
+
+/// > nest here
+/// >
+/// > > nest here
+/// > lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn two() {}
+
+/// > nest here
+/// >
+/// > > nest here
+/// lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn three() {}
+
+/// >   * > nest here
+/// lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn four() {}
+
+/// > * > nest here
+/// lazy continuation
+//~^ ERROR: doc quote missing `>` marker
+fn four_point_1() {}
+
+/// * > nest here lazy continuation
+fn five() {}
+
+/// 1. > nest here
+///  lazy continuation (this results in strange indentation, but still works)
+//~^ ERROR: doc quote missing `>` marker
+fn six() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr
new file mode 100644
index 0000000..975184a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_blockquote.stderr
@@ -0,0 +1,76 @@
+error: doc quote missing `>` marker
+  --> tests/ui/doc/doc_lazy_blockquote.rs:4:5
+   |
+LL | /// lazy continuation
+   |     ^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+   = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]`
+help: add markers to start of line
+   |
+LL | /// > lazy continuation
+   |     +
+
+error: doc quote missing `>` marker
+  --> tests/ui/doc/doc_lazy_blockquote.rs:20:5
+   |
+LL | /// > lazy continuation
+   |     ^^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+help: add markers to start of line
+   |
+LL | /// > > lazy continuation
+   |       +
+
+error: doc quote missing `>` marker
+  --> tests/ui/doc/doc_lazy_blockquote.rs:27:5
+   |
+LL | /// lazy continuation
+   |     ^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+help: add markers to start of line
+   |
+LL | /// > > lazy continuation
+   |     +++
+
+error: doc quote missing `>` marker
+  --> tests/ui/doc/doc_lazy_blockquote.rs:32:5
+   |
+LL | /// lazy continuation
+   |     ^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+help: add markers to start of line
+   |
+LL | /// >     > lazy continuation
+   |     +++++++
+
+error: doc quote missing `>` marker
+  --> tests/ui/doc/doc_lazy_blockquote.rs:37:5
+   |
+LL | /// lazy continuation
+   |     ^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+help: add markers to start of line
+   |
+LL | /// >   > lazy continuation
+   |     +++++
+
+error: doc quote missing `>` marker
+  --> tests/ui/doc/doc_lazy_blockquote.rs:45:5
+   |
+LL | ///  lazy continuation (this results in strange indentation, but still works)
+   |     ^
+   |
+   = help: if this not intended to be a quote at all, escape it with `\>`
+help: add markers to start of line
+   |
+LL | ///    > lazy continuation (this results in strange indentation, but still works)
+   |        +
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed
new file mode 100644
index 0000000..409e6b0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.fixed
@@ -0,0 +1,77 @@
+#![warn(clippy::doc_lazy_continuation)]
+
+/// 1. nest here
+///    lazy continuation
+//~^ ERROR: doc list item missing indentation
+fn one() {}
+
+/// 1. first line
+///    lazy list continuations don't make warnings with this lint
+//~^ ERROR: doc list item missing indentation
+///    because they don't have the
+//~^ ERROR: doc list item missing indentation
+fn two() {}
+
+///   - nest here
+///     lazy continuation
+//~^ ERROR: doc list item missing indentation
+fn three() {}
+
+///   - first line
+///     lazy list continuations don't make warnings with this lint
+//~^ ERROR: doc list item missing indentation
+///     because they don't have the
+//~^ ERROR: doc list item missing indentation
+fn four() {}
+
+///   - nest here
+///     lazy continuation
+//~^ ERROR: doc list item missing indentation
+fn five() {}
+
+///   - - first line
+///       this will warn on the lazy continuation
+//~^ ERROR: doc list item missing indentation
+///       and so should this
+//~^ ERROR: doc list item missing indentation
+fn six() {}
+
+///   - - first line
+///
+///     this is not a lazy continuation
+fn seven() {}
+
+#[rustfmt::skip]
+// https://github.com/rust-lang/rust-clippy/pull/12770#issuecomment-2118601768
+/// Returns a list of ProtocolDescriptors from a Serde JSON input.
+///
+/// Defined Protocol Identifiers for the Protocol Descriptor
+/// We intentionally omit deprecated profile identifiers.
+/// From Bluetooth Assigned Numbers:
+/// https://www.bluetooth.com/specifications/assigned-numbers/service-discovery
+///
+/// # Arguments
+/// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors
+///     to set up. Example:
+///   'protocol_descriptors': [
+//~^ ERROR: doc list item missing indentation
+///      {
+///          'protocol': 25,  # u64 Representation of ProtocolIdentifier::AVDTP
+///          'params': [
+///              {
+///                 'data': 0x0103  # to indicate 1.3
+///              },
+///              {
+///                  'data': 0x0105  # to indicate 1.5
+///              }
+///          ]
+///      },
+///      {
+///          'protocol': 1,  # u64 Representation of ProtocolIdentifier::SDP
+///          'params': [{
+///              'data': 0x0019
+///          }]
+///      }
+///   ]
+//~^ ERROR: doc list item missing indentation
+fn eight() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs b/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs
new file mode 100644
index 0000000..30ab448
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.rs
@@ -0,0 +1,77 @@
+#![warn(clippy::doc_lazy_continuation)]
+
+/// 1. nest here
+/// lazy continuation
+//~^ ERROR: doc list item missing indentation
+fn one() {}
+
+/// 1. first line
+/// lazy list continuations don't make warnings with this lint
+//~^ ERROR: doc list item missing indentation
+/// because they don't have the
+//~^ ERROR: doc list item missing indentation
+fn two() {}
+
+///   - nest here
+/// lazy continuation
+//~^ ERROR: doc list item missing indentation
+fn three() {}
+
+///   - first line
+/// lazy list continuations don't make warnings with this lint
+//~^ ERROR: doc list item missing indentation
+/// because they don't have the
+//~^ ERROR: doc list item missing indentation
+fn four() {}
+
+///   - nest here
+/// lazy continuation
+//~^ ERROR: doc list item missing indentation
+fn five() {}
+
+///   - - first line
+/// this will warn on the lazy continuation
+//~^ ERROR: doc list item missing indentation
+///     and so should this
+//~^ ERROR: doc list item missing indentation
+fn six() {}
+
+///   - - first line
+///
+///     this is not a lazy continuation
+fn seven() {}
+
+#[rustfmt::skip]
+// https://github.com/rust-lang/rust-clippy/pull/12770#issuecomment-2118601768
+/// Returns a list of ProtocolDescriptors from a Serde JSON input.
+///
+/// Defined Protocol Identifiers for the Protocol Descriptor
+/// We intentionally omit deprecated profile identifiers.
+/// From Bluetooth Assigned Numbers:
+/// https://www.bluetooth.com/specifications/assigned-numbers/service-discovery
+///
+/// # Arguments
+/// * `protocol_descriptors`: A Json Representation of the ProtocolDescriptors
+///     to set up. Example:
+///  'protocol_descriptors': [
+//~^ ERROR: doc list item missing indentation
+///      {
+///          'protocol': 25,  # u64 Representation of ProtocolIdentifier::AVDTP
+///          'params': [
+///              {
+///                 'data': 0x0103  # to indicate 1.3
+///              },
+///              {
+///                  'data': 0x0105  # to indicate 1.5
+///              }
+///          ]
+///      },
+///      {
+///          'protocol': 1,  # u64 Representation of ProtocolIdentifier::SDP
+///          'params': [{
+///              'data': 0x0019
+///          }]
+///      }
+///  ]
+//~^ ERROR: doc list item missing indentation
+fn eight() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr
new file mode 100644
index 0000000..ddfdc49
--- /dev/null
+++ b/src/tools/clippy/tests/ui/doc/doc_lazy_list.stderr
@@ -0,0 +1,136 @@
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:4:5
+   |
+LL | /// lazy continuation
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+   = note: `-D clippy::doc-lazy-continuation` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::doc_lazy_continuation)]`
+help: indent this line
+   |
+LL | ///    lazy continuation
+   |     +++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:9:5
+   |
+LL | /// lazy list continuations don't make warnings with this lint
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///    lazy list continuations don't make warnings with this lint
+   |     +++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:11:5
+   |
+LL | /// because they don't have the
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///    because they don't have the
+   |     +++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:16:5
+   |
+LL | /// lazy continuation
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///     lazy continuation
+   |     ++++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:21:5
+   |
+LL | /// lazy list continuations don't make warnings with this lint
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///     lazy list continuations don't make warnings with this lint
+   |     ++++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:23:5
+   |
+LL | /// because they don't have the
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///     because they don't have the
+   |     ++++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:28:5
+   |
+LL | /// lazy continuation
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///     lazy continuation
+   |     ++++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:33:5
+   |
+LL | /// this will warn on the lazy continuation
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///       this will warn on the lazy continuation
+   |     ++++++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:35:5
+   |
+LL | ///     and so should this
+   |     ^^^^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///       and so should this
+   |         ++
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:56:5
+   |
+LL | ///  'protocol_descriptors': [
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///   'protocol_descriptors': [
+   |      +
+
+error: doc list item missing indentation
+  --> tests/ui/doc/doc_lazy_list.rs:75:5
+   |
+LL | ///  ]
+   |     ^
+   |
+   = help: if this is supposed to be its own paragraph, add a blank line
+help: indent this line
+   |
+LL | ///   ]
+   |      +
+
+error: aborting due to 11 previous errors
+
diff --git a/src/tools/clippy/tests/ui/duplicated_attributes.rs b/src/tools/clippy/tests/ui/duplicated_attributes.rs
index d51e7e3..97cf4a6 100644
--- a/src/tools/clippy/tests/ui/duplicated_attributes.rs
+++ b/src/tools/clippy/tests/ui/duplicated_attributes.rs
@@ -1,5 +1,5 @@
 //@aux-build:proc_macro_attr.rs
-
+#![feature(rustc_attrs)]
 #![warn(clippy::duplicated_attributes)]
 #![cfg(any(unix, windows))]
 #![allow(dead_code)]
@@ -20,6 +20,10 @@
 #[cfg(unix)] // cfgs are not handled
 fn bar() {}
 
+// No warning:
+#[rustc_on_unimplemented(on(_Self = "&str", label = "`a"), on(_Self = "alloc::string::String", label = "a"))]
+trait Abc {}
+
 #[proc_macro_attr::duplicated_attr()] // Should not warn!
 fn babar() {}
 
diff --git a/src/tools/clippy/tests/ui/eager_transmute.fixed b/src/tools/clippy/tests/ui/eager_transmute.fixed
index c29e7dd..ba43424 100644
--- a/src/tools/clippy/tests/ui/eager_transmute.fixed
+++ b/src/tools/clippy/tests/ui/eager_transmute.fixed
@@ -2,7 +2,7 @@
 #![warn(clippy::eager_transmute)]
 #![allow(clippy::transmute_int_to_non_zero, clippy::missing_transmute_annotations)]
 
-use std::num::NonZeroU8;
+use std::num::NonZero;
 
 #[repr(u8)]
 enum Opcode {
@@ -85,21 +85,21 @@
 }
 impls!(NonMaxU8, NonZeroNonMaxU8);
 
-fn niche_tests(v1: u8, v2: NonZeroU8, v3: NonZeroNonMaxU8) {
-    // u8 -> NonZeroU8, do lint
-    let _: Option<NonZeroU8> = (v1 > 0).then(|| unsafe { std::mem::transmute(v1) });
+fn niche_tests(v1: u8, v2: NonZero<u8>, v3: NonZeroNonMaxU8) {
+    // u8 -> NonZero<u8>, do lint
+    let _: Option<NonZero<u8>> = (v1 > 0).then(|| unsafe { std::mem::transmute(v1) });
 
-    // NonZeroU8 -> u8, don't lint, target type has no niche and therefore a higher validity range
-    let _: Option<u8> = (v2 > NonZeroU8::new(1).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
+    // NonZero<u8> -> u8, don't lint, target type has no niche and therefore a higher validity range
+    let _: Option<u8> = (v2 > NonZero::new(1u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
 
-    // NonZeroU8 -> NonMaxU8, do lint, different niche
-    let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
+    // NonZero<u8> -> NonMaxU8, do lint, different niche
+    let _: Option<NonMaxU8> = (v2 < NonZero::new(255u8).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
 
     // NonZeroNonMaxU8 -> NonMaxU8, don't lint, target type has more validity
     let _: Option<NonMaxU8> = (v3 < 255).then_some(unsafe { std::mem::transmute(v2) });
 
-    // NonZeroU8 -> NonZeroNonMaxU8, do lint, target type has less validity
-    let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
+    // NonZero<u8> -> NonZeroNonMaxU8, do lint, target type has less validity
+    let _: Option<NonZeroNonMaxU8> = (v2 < NonZero::new(255u8).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/eager_transmute.rs b/src/tools/clippy/tests/ui/eager_transmute.rs
index 491a948..9750e87 100644
--- a/src/tools/clippy/tests/ui/eager_transmute.rs
+++ b/src/tools/clippy/tests/ui/eager_transmute.rs
@@ -2,7 +2,7 @@
 #![warn(clippy::eager_transmute)]
 #![allow(clippy::transmute_int_to_non_zero, clippy::missing_transmute_annotations)]
 
-use std::num::NonZeroU8;
+use std::num::NonZero;
 
 #[repr(u8)]
 enum Opcode {
@@ -85,21 +85,21 @@
 }
 impls!(NonMaxU8, NonZeroNonMaxU8);
 
-fn niche_tests(v1: u8, v2: NonZeroU8, v3: NonZeroNonMaxU8) {
-    // u8 -> NonZeroU8, do lint
-    let _: Option<NonZeroU8> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) });
+fn niche_tests(v1: u8, v2: NonZero<u8>, v3: NonZeroNonMaxU8) {
+    // u8 -> NonZero<u8>, do lint
+    let _: Option<NonZero<u8>> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) });
 
-    // NonZeroU8 -> u8, don't lint, target type has no niche and therefore a higher validity range
-    let _: Option<u8> = (v2 > NonZeroU8::new(1).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
+    // NonZero<u8> -> u8, don't lint, target type has no niche and therefore a higher validity range
+    let _: Option<u8> = (v2 > NonZero::new(1u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
 
-    // NonZeroU8 -> NonMaxU8, do lint, different niche
-    let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
+    // NonZero<u8> -> NonMaxU8, do lint, different niche
+    let _: Option<NonMaxU8> = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
 
     // NonZeroNonMaxU8 -> NonMaxU8, don't lint, target type has more validity
     let _: Option<NonMaxU8> = (v3 < 255).then_some(unsafe { std::mem::transmute(v2) });
 
-    // NonZeroU8 -> NonZeroNonMaxU8, do lint, target type has less validity
-    let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
+    // NonZero<u8> -> NonZeroNonMaxU8, do lint, target type has less validity
+    let _: Option<NonZeroNonMaxU8> = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
 }
 
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/eager_transmute.stderr b/src/tools/clippy/tests/ui/eager_transmute.stderr
index b9a4321..5cf7bd4 100644
--- a/src/tools/clippy/tests/ui/eager_transmute.stderr
+++ b/src/tools/clippy/tests/ui/eager_transmute.stderr
@@ -155,36 +155,36 @@
    |              ~~~~ ++
 
 error: this transmute is always evaluated eagerly, even if the condition is false
-  --> tests/ui/eager_transmute.rs:90:60
+  --> tests/ui/eager_transmute.rs:90:62
    |
-LL |     let _: Option<NonZeroU8> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) });
-   |                                                            ^^^^^^^^^^^^^^^^^^^^^^^
+LL |     let _: Option<NonZero<u8>> = (v1 > 0).then_some(unsafe { std::mem::transmute(v1) });
+   |                                                              ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider using `bool::then` to only transmute if the condition holds
    |
-LL |     let _: Option<NonZeroU8> = (v1 > 0).then(|| unsafe { std::mem::transmute(v1) });
-   |                                         ~~~~ ++
+LL |     let _: Option<NonZero<u8>> = (v1 > 0).then(|| unsafe { std::mem::transmute(v1) });
+   |                                           ~~~~ ++
 
 error: this transmute is always evaluated eagerly, even if the condition is false
   --> tests/ui/eager_transmute.rs:96:86
    |
-LL |     let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
+LL |     let _: Option<NonMaxU8> = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
    |                                                                                      ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider using `bool::then` to only transmute if the condition holds
    |
-LL |     let _: Option<NonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
+LL |     let _: Option<NonMaxU8> = (v2 < NonZero::new(255u8).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
    |                                                                   ~~~~ ++
 
 error: this transmute is always evaluated eagerly, even if the condition is false
   --> tests/ui/eager_transmute.rs:102:93
    |
-LL |     let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
+LL |     let _: Option<NonZeroNonMaxU8> = (v2 < NonZero::new(255u8).unwrap()).then_some(unsafe { std::mem::transmute(v2) });
    |                                                                                             ^^^^^^^^^^^^^^^^^^^^^^^
    |
 help: consider using `bool::then` to only transmute if the condition holds
    |
-LL |     let _: Option<NonZeroNonMaxU8> = (v2 < NonZeroU8::new(255).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
+LL |     let _: Option<NonZeroNonMaxU8> = (v2 < NonZero::new(255u8).unwrap()).then(|| unsafe { std::mem::transmute(v2) });
    |                                                                          ~~~~ ++
 
 error: aborting due to 17 previous errors
diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.fixed b/src/tools/clippy/tests/ui/from_str_radix_10.fixed
index 8c253bf..f9ce1de 100644
--- a/src/tools/clippy/tests/ui/from_str_radix_10.fixed
+++ b/src/tools/clippy/tests/ui/from_str_radix_10.fixed
@@ -1,3 +1,4 @@
+#![feature(const_int_from_str)]
 #![warn(clippy::from_str_radix_10)]
 
 mod some_mod {
@@ -59,3 +60,13 @@
 
     Ok(())
 }
+
+fn issue_12732() {
+    const A: Result<u32, std::num::ParseIntError> = u32::from_str_radix("123", 10);
+    const B: () = {
+        let _ = u32::from_str_radix("123", 10);
+    };
+    const fn foo() {
+        let _ = u32::from_str_radix("123", 10);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.rs b/src/tools/clippy/tests/ui/from_str_radix_10.rs
index e9d0221..2d5b351 100644
--- a/src/tools/clippy/tests/ui/from_str_radix_10.rs
+++ b/src/tools/clippy/tests/ui/from_str_radix_10.rs
@@ -1,3 +1,4 @@
+#![feature(const_int_from_str)]
 #![warn(clippy::from_str_radix_10)]
 
 mod some_mod {
@@ -59,3 +60,13 @@
 
     Ok(())
 }
+
+fn issue_12732() {
+    const A: Result<u32, std::num::ParseIntError> = u32::from_str_radix("123", 10);
+    const B: () = {
+        let _ = u32::from_str_radix("123", 10);
+    };
+    const fn foo() {
+        let _ = u32::from_str_radix("123", 10);
+    }
+}
diff --git a/src/tools/clippy/tests/ui/from_str_radix_10.stderr b/src/tools/clippy/tests/ui/from_str_radix_10.stderr
index 4aa84ec..01a1bf8 100644
--- a/src/tools/clippy/tests/ui/from_str_radix_10.stderr
+++ b/src/tools/clippy/tests/ui/from_str_radix_10.stderr
@@ -1,5 +1,5 @@
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:28:5
+  --> tests/ui/from_str_radix_10.rs:29:5
    |
 LL |     u32::from_str_radix("30", 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"30".parse::<u32>()`
@@ -8,43 +8,43 @@
    = help: to override `-D warnings` add `#[allow(clippy::from_str_radix_10)]`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:31:5
+  --> tests/ui/from_str_radix_10.rs:32:5
    |
 LL |     i64::from_str_radix("24", 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"24".parse::<i64>()`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:33:5
+  --> tests/ui/from_str_radix_10.rs:34:5
    |
 LL |     isize::from_str_radix("100", 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"100".parse::<isize>()`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:35:5
+  --> tests/ui/from_str_radix_10.rs:36:5
    |
 LL |     u8::from_str_radix("7", 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `"7".parse::<u8>()`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:37:5
+  --> tests/ui/from_str_radix_10.rs:38:5
    |
 LL |     u16::from_str_radix(&("10".to_owned() + "5"), 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `("10".to_owned() + "5").parse::<u16>()`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:39:5
+  --> tests/ui/from_str_radix_10.rs:40:5
    |
 LL |     i128::from_str_radix(Test + Test, 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(Test + Test).parse::<i128>()`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:43:5
+  --> tests/ui/from_str_radix_10.rs:44:5
    |
 LL |     i32::from_str_radix(string, 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.parse::<i32>()`
 
 error: this call to `from_str_radix` can be replaced with a call to `str::parse`
-  --> tests/ui/from_str_radix_10.rs:47:5
+  --> tests/ui/from_str_radix_10.rs:48:5
    |
 LL |     i32::from_str_radix(&stringier, 10)?;
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `stringier.parse::<i32>()`
diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed
index c03d91c..72b39c9 100644
--- a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed
+++ b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed
@@ -11,7 +11,6 @@
 
     let _ = vec![1, 2, 3].into_iter();
     let _ = (&vec![1, 2, 3]).iter(); //~ ERROR: equivalent to `.iter()
-    let _ = vec![1, 2, 3].into_boxed_slice().iter(); //~ ERROR: equivalent to `.iter()
     let _ = std::rc::Rc::from(&[X][..]).iter(); //~ ERROR: equivalent to `.iter()
     let _ = std::sync::Arc::from(&[X][..]).iter(); //~ ERROR: equivalent to `.iter()
 
diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.rs b/src/tools/clippy/tests/ui/into_iter_on_ref.rs
index 93c732f..5ba2247 100644
--- a/src/tools/clippy/tests/ui/into_iter_on_ref.rs
+++ b/src/tools/clippy/tests/ui/into_iter_on_ref.rs
@@ -11,7 +11,6 @@
 
     let _ = vec![1, 2, 3].into_iter();
     let _ = (&vec![1, 2, 3]).into_iter(); //~ ERROR: equivalent to `.iter()
-    let _ = vec![1, 2, 3].into_boxed_slice().into_iter(); //~ ERROR: equivalent to `.iter()
     let _ = std::rc::Rc::from(&[X][..]).into_iter(); //~ ERROR: equivalent to `.iter()
     let _ = std::sync::Arc::from(&[X][..]).into_iter(); //~ ERROR: equivalent to `.iter()
 
diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr
index 0e9d485..64d8140 100644
--- a/src/tools/clippy/tests/ui/into_iter_on_ref.stderr
+++ b/src/tools/clippy/tests/ui/into_iter_on_ref.stderr
@@ -8,160 +8,154 @@
    = help: to override `-D warnings` add `#[allow(clippy::into_iter_on_ref)]`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice`
-  --> tests/ui/into_iter_on_ref.rs:14:46
-   |
-LL |     let _ = vec![1, 2, 3].into_boxed_slice().into_iter();
-   |                                              ^^^^^^^^^ help: call directly: `iter`
-
-error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice`
-  --> tests/ui/into_iter_on_ref.rs:15:41
+  --> tests/ui/into_iter_on_ref.rs:14:41
    |
 LL |     let _ = std::rc::Rc::from(&[X][..]).into_iter();
    |                                         ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `slice`
-  --> tests/ui/into_iter_on_ref.rs:16:44
+  --> tests/ui/into_iter_on_ref.rs:15:44
    |
 LL |     let _ = std::sync::Arc::from(&[X][..]).into_iter();
    |                                            ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array`
-  --> tests/ui/into_iter_on_ref.rs:18:32
+  --> tests/ui/into_iter_on_ref.rs:17:32
    |
 LL |     let _ = (&&&&&&&[1, 2, 3]).into_iter();
    |                                ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array`
-  --> tests/ui/into_iter_on_ref.rs:19:36
+  --> tests/ui/into_iter_on_ref.rs:18:36
    |
 LL |     let _ = (&&&&mut &&&[1, 2, 3]).into_iter();
    |                                    ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `array`
-  --> tests/ui/into_iter_on_ref.rs:20:40
+  --> tests/ui/into_iter_on_ref.rs:19:40
    |
 LL |     let _ = (&mut &mut &mut [1, 2, 3]).into_iter();
    |                                        ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Option`
-  --> tests/ui/into_iter_on_ref.rs:22:24
+  --> tests/ui/into_iter_on_ref.rs:21:24
    |
 LL |     let _ = (&Some(4)).into_iter();
    |                        ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Option`
-  --> tests/ui/into_iter_on_ref.rs:23:28
+  --> tests/ui/into_iter_on_ref.rs:22:28
    |
 LL |     let _ = (&mut Some(5)).into_iter();
    |                            ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Result`
-  --> tests/ui/into_iter_on_ref.rs:24:32
+  --> tests/ui/into_iter_on_ref.rs:23:32
    |
 LL |     let _ = (&Ok::<_, i32>(6)).into_iter();
    |                                ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Result`
-  --> tests/ui/into_iter_on_ref.rs:25:37
+  --> tests/ui/into_iter_on_ref.rs:24:37
    |
 LL |     let _ = (&mut Err::<i32, _>(7)).into_iter();
    |                                     ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Vec`
-  --> tests/ui/into_iter_on_ref.rs:26:34
+  --> tests/ui/into_iter_on_ref.rs:25:34
    |
 LL |     let _ = (&Vec::<i32>::new()).into_iter();
    |                                  ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `Vec`
-  --> tests/ui/into_iter_on_ref.rs:27:38
+  --> tests/ui/into_iter_on_ref.rs:26:38
    |
 LL |     let _ = (&mut Vec::<i32>::new()).into_iter();
    |                                      ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeMap`
-  --> tests/ui/into_iter_on_ref.rs:28:44
+  --> tests/ui/into_iter_on_ref.rs:27:44
    |
 LL |     let _ = (&BTreeMap::<i32, u64>::new()).into_iter();
    |                                            ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `BTreeMap`
-  --> tests/ui/into_iter_on_ref.rs:29:48
+  --> tests/ui/into_iter_on_ref.rs:28:48
    |
 LL |     let _ = (&mut BTreeMap::<i32, u64>::new()).into_iter();
    |                                                ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `VecDeque`
-  --> tests/ui/into_iter_on_ref.rs:30:39
+  --> tests/ui/into_iter_on_ref.rs:29:39
    |
 LL |     let _ = (&VecDeque::<i32>::new()).into_iter();
    |                                       ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `VecDeque`
-  --> tests/ui/into_iter_on_ref.rs:31:43
+  --> tests/ui/into_iter_on_ref.rs:30:43
    |
 LL |     let _ = (&mut VecDeque::<i32>::new()).into_iter();
    |                                           ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `LinkedList`
-  --> tests/ui/into_iter_on_ref.rs:32:41
+  --> tests/ui/into_iter_on_ref.rs:31:41
    |
 LL |     let _ = (&LinkedList::<i32>::new()).into_iter();
    |                                         ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `LinkedList`
-  --> tests/ui/into_iter_on_ref.rs:33:45
+  --> tests/ui/into_iter_on_ref.rs:32:45
    |
 LL |     let _ = (&mut LinkedList::<i32>::new()).into_iter();
    |                                             ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashMap`
-  --> tests/ui/into_iter_on_ref.rs:34:43
+  --> tests/ui/into_iter_on_ref.rs:33:43
    |
 LL |     let _ = (&HashMap::<i32, u64>::new()).into_iter();
    |                                           ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter_mut()` and will not consume the `HashMap`
-  --> tests/ui/into_iter_on_ref.rs:35:47
+  --> tests/ui/into_iter_on_ref.rs:34:47
    |
 LL |     let _ = (&mut HashMap::<i32, u64>::new()).into_iter();
    |                                               ^^^^^^^^^ help: call directly: `iter_mut`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BTreeSet`
-  --> tests/ui/into_iter_on_ref.rs:37:39
+  --> tests/ui/into_iter_on_ref.rs:36:39
    |
 LL |     let _ = (&BTreeSet::<i32>::new()).into_iter();
    |                                       ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `BinaryHeap`
-  --> tests/ui/into_iter_on_ref.rs:38:41
+  --> tests/ui/into_iter_on_ref.rs:37:41
    |
 LL |     let _ = (&BinaryHeap::<i32>::new()).into_iter();
    |                                         ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `HashSet`
-  --> tests/ui/into_iter_on_ref.rs:39:38
+  --> tests/ui/into_iter_on_ref.rs:38:38
    |
 LL |     let _ = (&HashSet::<i32>::new()).into_iter();
    |                                      ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `Path`
-  --> tests/ui/into_iter_on_ref.rs:40:43
+  --> tests/ui/into_iter_on_ref.rs:39:43
    |
 LL |     let _ = std::path::Path::new("12/34").into_iter();
    |                                           ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `PathBuf`
-  --> tests/ui/into_iter_on_ref.rs:41:47
+  --> tests/ui/into_iter_on_ref.rs:40:47
    |
 LL |     let _ = std::path::PathBuf::from("12/34").into_iter();
    |                                               ^^^^^^^^^ help: call directly: `iter`
 
 error: this `.into_iter()` call is equivalent to `.iter()` and will not consume the `array`
-  --> tests/ui/into_iter_on_ref.rs:43:26
+  --> tests/ui/into_iter_on_ref.rs:42:26
    |
 LL |     let _ = (&[1, 2, 3]).into_iter().next();
    |                          ^^^^^^^^^ help: call directly: `iter`
 
-error: aborting due to 27 previous errors
+error: aborting due to 26 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_same_arms.stderr b/src/tools/clippy/tests/ui/match_same_arms.stderr
index a926570..3c03827 100644
--- a/src/tools/clippy/tests/ui/match_same_arms.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms.stderr
@@ -2,7 +2,7 @@
   --> tests/ui/match_same_arms.rs:12:9
    |
 LL |         Abc::A => 0,
-   |         ^^^^^^^^^^^ help: try removing the arm
+   |         ^^^^^^^^^^^^^ help: try removing the arm
    |
    = help: or try changing either arm body
 note: `_` wildcard arm here
@@ -17,106 +17,114 @@
   --> tests/ui/match_same_arms.rs:18:9
    |
 LL |         (1, .., 3) => 42,
-   |         ----------^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `(1, .., 3) | (.., 3)`
+   |         ^^^^^^^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms.rs:19:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
    |
-LL |         (.., 3) => 42,
-   |         ^^^^^^^^^^^^^
+LL |         (1, .., 3) | (.., 3) => 42,
+   |         ~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         (.., 3) => 42,
+   |
 
 error: this match arm has an identical body to another arm
   --> tests/ui/match_same_arms.rs:25:9
    |
 LL |         51 => 1,
-   |         --^^^^^
-   |         |
-   |         help: try merging the arm patterns: `51 | 42`
-   |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms.rs:24:9
-   |
-LL |         42 => 1,
    |         ^^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         51 | 42 => 1,
+   |         ~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         42 => 1,
+   |
 
 error: this match arm has an identical body to another arm
   --> tests/ui/match_same_arms.rs:26:9
    |
 LL |         41 => 2,
-   |         --^^^^^
-   |         |
-   |         help: try merging the arm patterns: `41 | 52`
-   |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms.rs:27:9
-   |
-LL |         52 => 2,
    |         ^^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         41 | 52 => 2,
+   |         ~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         52 => 2,
+   |
 
 error: this match arm has an identical body to another arm
   --> tests/ui/match_same_arms.rs:33:9
    |
 LL |         2 => 2,
-   |         -^^^^^
-   |         |
-   |         help: try merging the arm patterns: `2 | 1`
-   |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms.rs:32:9
-   |
-LL |         1 => 2,
    |         ^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         2 | 1 => 2,
+   |         ~~~~~
+help: and remove this obsolete arm
+   |
+LL -         1 => 2,
+   |
 
 error: this match arm has an identical body to another arm
   --> tests/ui/match_same_arms.rs:35:9
    |
 LL |         3 => 2,
-   |         -^^^^^
-   |         |
-   |         help: try merging the arm patterns: `3 | 1`
-   |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms.rs:32:9
-   |
-LL |         1 => 2,
    |         ^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         3 | 1 => 2,
+   |         ~~~~~
+help: and remove this obsolete arm
+   |
+LL -         1 => 2,
+   |
 
 error: this match arm has an identical body to another arm
   --> tests/ui/match_same_arms.rs:33:9
    |
 LL |         2 => 2,
-   |         -^^^^^
-   |         |
-   |         help: try merging the arm patterns: `2 | 3`
-   |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms.rs:35:9
-   |
-LL |         3 => 2,
    |         ^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         2 | 3 => 2,
+   |         ~~~~~
+help: and remove this obsolete arm
+   |
+LL -         3 => 2,
+LL +
+   |
 
 error: this match arm has an identical body to another arm
   --> tests/ui/match_same_arms.rs:52:17
    |
 LL |                 CommandInfo::External { name, .. } => name.to_string(),
-   |                 ----------------------------------^^^^^^^^^^^^^^^^^^^^
-   |                 |
-   |                 help: try merging the arm patterns: `CommandInfo::External { name, .. } | CommandInfo::BuiltIn { name, .. }`
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms.rs:51:17
+   = help: try changing either arm body
+help: or try merging the arm patterns
    |
-LL |                 CommandInfo::BuiltIn { name, .. } => name.to_string(),
-   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL |                 CommandInfo::External { name, .. } | CommandInfo::BuiltIn { name, .. } => name.to_string(),
+   |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -                 CommandInfo::BuiltIn { name, .. } => name.to_string(),
+   |
 
 error: aborting due to 8 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.fixed b/src/tools/clippy/tests/ui/match_same_arms2.fixed
new file mode 100644
index 0000000..fba0cf3
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_same_arms2.fixed
@@ -0,0 +1,241 @@
+#![warn(clippy::match_same_arms)]
+#![allow(
+    clippy::disallowed_names,
+    clippy::diverging_sub_expression,
+    clippy::uninlined_format_args,
+    clippy::match_single_binding,
+    clippy::match_like_matches_macro
+)]
+fn bar<T>(_: T) {}
+fn foo() -> bool {
+    unimplemented!()
+}
+
+fn match_same_arms() {
+    let _ = match 42 {
+        _ => {
+            foo();
+            let mut a = 42 + [23].len() as i32;
+            if true {
+                a += 7;
+            }
+            a = -31 - a;
+            a
+        },
+    };
+    //~^^^^^^^^^^^^^^^^^^^ ERROR: this match arm has an identical body to the `_` wildcard arm
+
+    let _ = match 42 {
+        51 | 42 => foo(), //~ ERROR: this match arm has an identical body to another arm
+        _ => true,
+    };
+
+    let _ = match Some(42) {
+        None | Some(_) => 24, //~ ERROR: this match arm has an identical body to another arm
+    };
+
+    let _ = match Some(42) {
+        Some(foo) => 24,
+        None => 24,
+    };
+
+    let _ = match Some(42) {
+        Some(42) => 24,
+        Some(a) => 24, // bindings are different
+        None => 0,
+    };
+
+    let _ = match Some(42) {
+        Some(a) if a > 0 => 24,
+        Some(a) => 24, // one arm has a guard
+        None => 0,
+    };
+
+    match (Some(42), Some(42)) {
+        (None, Some(a)) | (Some(a), None) => bar(a), //~ ERROR: this match arm has an identical body to another arm
+        _ => (),
+    }
+
+    // No warning because guards are different
+    let _ = match Some(42) {
+        Some(a) if a == 42 => a,
+        Some(a) if a == 24 => a,
+        Some(_) => 24,
+        None => 0,
+    };
+
+    let _ = match (Some(42), Some(42)) {
+        (None, Some(a)) | (Some(a), None) if a == 42 => a, //~ ERROR: this match arm has an identical body to another arm
+        _ => 0,
+    };
+
+    match (Some(42), Some(42)) {
+        (Some(a), ..) | (.., Some(a)) => bar(a), //~ ERROR: this match arm has an identical body to another arm
+        _ => (),
+    }
+
+    let _ = match Some(()) {
+        Some(()) => 0.0,
+        None => -0.0,
+    };
+
+    match (Some(42), Some("")) {
+        (Some(a), None) => bar(a),
+        (None, Some(a)) => bar(a), // bindings have different types
+        _ => (),
+    }
+
+    let x: Result<i32, &str> = Ok(3);
+
+    // No warning because of the guard.
+    match x {
+        Ok(x) if x * x == 64 => println!("ok"),
+        Ok(_) => println!("ok"),
+        Err(_) => println!("err"),
+    }
+
+    // This used to be a false positive; see issue #1996.
+    match x {
+        Ok(3) => println!("ok"),
+        Ok(x) if x * x == 64 => println!("ok 64"),
+        Ok(_) => println!("ok"),
+        Err(_) => println!("err"),
+    }
+
+    match (x, Some(1i32)) {
+        (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x), //~ ERROR: this match arm has an identical body to another arm
+        _ => println!("err"),
+    }
+
+    // No warning; different types for `x`.
+    match (x, Some(1.0f64)) {
+        (Ok(x), Some(_)) => println!("ok {}", x),
+        (Ok(_), Some(x)) => println!("ok {}", x),
+        _ => println!("err"),
+    }
+
+    // False negative #2251.
+    match x {
+        Ok(_tmp) => println!("ok"),
+        Ok(_) | Ok(3) => println!("ok"), //~ ERROR: this match arm has an identical body to another arm
+        Err(_) => {
+            unreachable!();
+        },
+    }
+
+    // False positive #1390
+    macro_rules! empty {
+        ($e:expr) => {};
+    }
+    match 0 {
+        0 => {
+            empty!(0);
+        },
+        1 => {
+            empty!(1);
+        },
+        x => {
+            empty!(x);
+        },
+    };
+
+    // still lint if the tokens are the same
+    match 0 {
+        1 | 0 => {
+            empty!(0);
+        },
+        x => {
+            empty!(x);
+        },
+    }
+    //~^^^^^^^ ERROR: this match arm has an identical body to another arm
+
+    match_expr_like_matches_macro_priority();
+}
+
+fn match_expr_like_matches_macro_priority() {
+    enum E {
+        A,
+        B,
+        C,
+    }
+    let x = E::A;
+    let _ans = match x {
+        E::A => false,
+        E::B => false,
+        _ => true,
+    };
+}
+
+fn main() {
+    let _ = match Some(0) {
+        Some(0) => 0,
+        Some(1) => 1,
+        #[cfg(feature = "foo")]
+        Some(2) => 2,
+        _ => 1,
+    };
+
+    enum Foo {
+        X(u32),
+        Y(u32),
+        Z(u32),
+    }
+
+    // Don't lint. `Foo::X(0)` and `Foo::Z(_)` overlap with the arm in between.
+    let _ = match Foo::X(0) {
+        Foo::X(0) => 1,
+        Foo::X(_) | Foo::Y(_) | Foo::Z(0) => 2,
+        Foo::Z(_) => 1,
+        _ => 0,
+    };
+
+    // Suggest moving `Foo::Z(_)` up.
+    let _ = match Foo::X(0) {
+        Foo::X(0) | Foo::Z(_) => 1, //~ ERROR: this match arm has an identical body to another arm
+        Foo::X(_) | Foo::Y(_) => 2,
+        _ => 0,
+    };
+
+    // Suggest moving `Foo::X(0)` down.
+    let _ = match Foo::X(0) {
+        Foo::Y(_) | Foo::Z(0) => 2,
+        Foo::Z(_) | Foo::X(0) => 1, //~ ERROR: this match arm has an identical body to another arm
+        _ => 0,
+    };
+
+    // Don't lint.
+    let _ = match 0 {
+        -2 => 1,
+        -5..=50 => 2,
+        -150..=88 => 1,
+        _ => 3,
+    };
+
+    struct Bar {
+        x: u32,
+        y: u32,
+        z: u32,
+    }
+
+    // Lint.
+    let _ = match None {
+        Some(Bar { y: 10, z: 0, .. }) => 2,
+        None => 50,
+        Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1, //~ ERROR: this match arm has an identical body to another arm
+        _ => 200,
+    };
+
+    let _ = match 0 {
+        0 => todo!(),
+        1 => todo!(),
+        2 => core::convert::identity::<u32>(todo!()),
+        3 => core::convert::identity::<u32>(todo!()),
+        _ => 5,
+    };
+
+    let _ = match 0 {
+        1 | 0 => cfg!(not_enable),
+        _ => false,
+    };
+}
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs
index 85ad096..8a4e3b3 100644
--- a/src/tools/clippy/tests/ui/match_same_arms2.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms2.rs
@@ -2,9 +2,10 @@
 #![allow(
     clippy::disallowed_names,
     clippy::diverging_sub_expression,
-    clippy::uninlined_format_args
+    clippy::uninlined_format_args,
+    clippy::match_single_binding,
+    clippy::match_like_matches_macro
 )]
-//@no-rustfix
 fn bar<T>(_: T) {}
 fn foo() -> bool {
     unimplemented!()
diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr
index f4c38c1..3d15176 100644
--- a/src/tools/clippy/tests/ui/match_same_arms2.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr
@@ -1,18 +1,18 @@
 error: this match arm has an identical body to the `_` wildcard arm
-  --> tests/ui/match_same_arms2.rs:15:9
+  --> tests/ui/match_same_arms2.rs:16:9
    |
 LL | /         42 => {
 LL | |             foo();
 LL | |             let mut a = 42 + [23].len() as i32;
 LL | |             if true {
 ...  |
-LL | |             a
 LL | |         },
-   | |_________^ help: try removing the arm
+LL | |         _ => {
+   | |________^ help: try removing the arm
    |
    = help: or try changing either arm body
 note: `_` wildcard arm here
-  --> tests/ui/match_same_arms2.rs:24:9
+  --> tests/ui/match_same_arms2.rs:25:9
    |
 LL | /         _ => {
 LL | |             foo();
@@ -26,203 +26,200 @@
    = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]`
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:38:9
+  --> tests/ui/match_same_arms2.rs:39:9
    |
 LL |         51 => foo(),
-   |         --^^^^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `51 | 42`
-   |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:37:9
-   |
-LL |         42 => foo(),
    |         ^^^^^^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         51 | 42 => foo(),
+   |         ~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         42 => foo(),
+   |
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:44:9
+  --> tests/ui/match_same_arms2.rs:45:9
    |
 LL |         None => 24,
-   |         ----^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `None | Some(_)`
+   |         ^^^^^^^^^^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:43:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
    |
-LL |         Some(_) => 24,
-   |         ^^^^^^^^^^^^^
+LL |         None | Some(_) => 24,
+   |         ~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         Some(_) => 24,
+   |
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:66:9
+  --> tests/ui/match_same_arms2.rs:67:9
    |
 LL |         (None, Some(a)) => bar(a),
-   |         ---------------^^^^^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `(None, Some(a)) | (Some(a), None)`
-   |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:65:9
-   |
-LL |         (Some(a), None) => bar(a),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         (None, Some(a)) | (Some(a), None) => bar(a),
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         (Some(a), None) => bar(a),
+   |
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:80:9
+  --> tests/ui/match_same_arms2.rs:81:9
    |
 LL |         (None, Some(a)) if a == 42 => a,
-   |         ---------------^^^^^^^^^^^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `(None, Some(a)) | (Some(a), None)`
-   |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:79:9
-   |
-LL |         (Some(a), None) if a == 42 => a,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         (None, Some(a)) | (Some(a), None) if a == 42 => a,
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         (Some(a), None) if a == 42 => a,
+   |
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:85:9
-   |
-LL |         (Some(a), ..) => bar(a),
-   |         -------------^^^^^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `(Some(a), ..) | (.., Some(a))`
-   |
-   = help: or try changing either arm body
-note: other arm here
   --> tests/ui/match_same_arms2.rs:86:9
    |
-LL |         (.., Some(a)) => bar(a),
+LL |         (Some(a), ..) => bar(a),
    |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         (Some(a), ..) | (.., Some(a)) => bar(a),
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         (.., Some(a)) => bar(a),
+   |
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:119:9
-   |
-LL |         (Ok(x), Some(_)) => println!("ok {}", x),
-   |         ----------------^^^^^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `(Ok(x), Some(_)) | (Ok(_), Some(x))`
-   |
-   = help: or try changing either arm body
-note: other arm here
   --> tests/ui/match_same_arms2.rs:120:9
    |
-LL |         (Ok(_), Some(x)) => println!("ok {}", x),
+LL |         (Ok(x), Some(_)) => println!("ok {}", x),
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         (Ok(x), Some(_)) | (Ok(_), Some(x)) => println!("ok {}", x),
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         (Ok(_), Some(x)) => println!("ok {}", x),
+   |
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:135:9
+  --> tests/ui/match_same_arms2.rs:136:9
    |
 LL |         Ok(_) => println!("ok"),
-   |         -----^^^^^^^^^^^^^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `Ok(_) | Ok(3)`
-   |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:134:9
-   |
-LL |         Ok(3) => println!("ok"),
    |         ^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         Ok(_) | Ok(3) => println!("ok"),
+   |         ~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         Ok(3) => println!("ok"),
+   |
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:162:9
+  --> tests/ui/match_same_arms2.rs:163:9
    |
-LL |           1 => {
-   |           ^ help: try merging the arm patterns: `1 | 0`
-   |  _________|
-   | |
+LL | /         1 => {
 LL | |             empty!(0);
 LL | |         },
    | |_________^
    |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:159:9
+   = help: try changing either arm body
+help: or try merging the arm patterns
    |
-LL | /         0 => {
-LL | |             empty!(0);
-LL | |         },
-   | |_________^
-
-error: match expression looks like `matches!` macro
-  --> tests/ui/match_same_arms2.rs:181:16
+LL |         1 | 0 => {
+   |         ~~~~~
+help: and remove this obsolete arm
    |
-LL |       let _ans = match x {
-   |  ________________^
-LL | |         E::A => false,
-LL | |         E::B => false,
-LL | |         _ => true,
-LL | |     };
-   | |_____^ help: try: `!matches!(x, E::A | E::B)`
+LL -         0 => {
+LL -             empty!(0);
+LL -         },
    |
-   = note: `-D clippy::match-like-matches-macro` implied by `-D warnings`
-   = help: to override `-D warnings` add `#[allow(clippy::match_like_matches_macro)]`
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:213:9
-   |
-LL |         Foo::X(0) => 1,
-   |         ---------^^^^^
-   |         |
-   |         help: try merging the arm patterns: `Foo::X(0) | Foo::Z(_)`
-   |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:215:9
-   |
-LL |         Foo::Z(_) => 1,
-   |         ^^^^^^^^^^^^^^
-
-error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:223:9
-   |
-LL |         Foo::Z(_) => 1,
-   |         ---------^^^^^
-   |         |
-   |         help: try merging the arm patterns: `Foo::Z(_) | Foo::X(0)`
-   |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:221:9
+  --> tests/ui/match_same_arms2.rs:214:9
    |
 LL |         Foo::X(0) => 1,
    |         ^^^^^^^^^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         Foo::X(0) | Foo::Z(_) => 1,
+   |         ~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         Foo::Z(_) => 1,
+   |
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:246:9
+  --> tests/ui/match_same_arms2.rs:224:9
+   |
+LL |         Foo::Z(_) => 1,
+   |         ^^^^^^^^^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         Foo::Z(_) | Foo::X(0) => 1,
+   |         ~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         Foo::X(0) => 1,
+   |
+
+error: this match arm has an identical body to another arm
+  --> tests/ui/match_same_arms2.rs:247:9
    |
 LL |         Some(Bar { y: 0, x: 5, .. }) => 1,
-   |         ----------------------------^^^^^
-   |         |
-   |         help: try merging the arm patterns: `Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. })`
-   |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:243:9
-   |
-LL |         Some(Bar { x: 0, y: 5, .. }) => 1,
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         Some(Bar { y: 0, x: 5, .. }) | Some(Bar { x: 0, y: 5, .. }) => 1,
+   |         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+help: and remove this obsolete arm
+   |
+LL -         Some(Bar { x: 0, y: 5, .. }) => 1,
+   |
 
 error: this match arm has an identical body to another arm
-  --> tests/ui/match_same_arms2.rs:260:9
+  --> tests/ui/match_same_arms2.rs:261:9
    |
 LL |         1 => cfg!(not_enable),
-   |         -^^^^^^^^^^^^^^^^^^^^
-   |         |
-   |         help: try merging the arm patterns: `1 | 0`
-   |
-   = help: or try changing either arm body
-note: other arm here
-  --> tests/ui/match_same_arms2.rs:259:9
-   |
-LL |         0 => cfg!(not_enable),
    |         ^^^^^^^^^^^^^^^^^^^^^
+   |
+   = help: try changing either arm body
+help: or try merging the arm patterns
+   |
+LL |         1 | 0 => cfg!(not_enable),
+   |         ~~~~~
+help: and remove this obsolete arm
+   |
+LL -         0 => cfg!(not_enable),
+   |
 
-error: aborting due to 14 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed
new file mode 100644
index 0000000..804c0a8
--- /dev/null
+++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.fixed
@@ -0,0 +1,61 @@
+#![feature(non_exhaustive_omitted_patterns_lint)]
+#![warn(clippy::match_same_arms)]
+#![no_main]
+use std::sync::atomic::Ordering; // #[non_exhaustive] enum
+
+fn repeat() -> ! {
+    panic!()
+}
+
+pub fn f(x: Ordering) {
+    #[deny(non_exhaustive_omitted_patterns)]
+    match x {
+        Ordering::Relaxed => println!("relaxed"),
+        Ordering::Release => println!("release"),
+        Ordering::Acquire => println!("acquire"),
+        Ordering::AcqRel | Ordering::SeqCst => repeat(),
+        _ => repeat(),
+    }
+}
+
+mod f {
+    #![deny(non_exhaustive_omitted_patterns)]
+
+    use super::*;
+
+    pub fn f(x: Ordering) {
+        match x {
+            Ordering::Relaxed => println!("relaxed"),
+            Ordering::Release => println!("release"),
+            Ordering::Acquire => println!("acquire"),
+            Ordering::AcqRel | Ordering::SeqCst => repeat(),
+            _ => repeat(),
+        }
+    }
+}
+
+// Below should still lint
+
+pub fn g(x: Ordering) {
+    match x {
+        Ordering::Relaxed => println!("relaxed"),
+        Ordering::Release => println!("release"),
+        Ordering::Acquire => println!("acquire"),
+        //~^ ERROR: this match arm has an identical body to the `_` wildcard arm
+        _ => repeat(),
+    }
+}
+
+mod g {
+    use super::*;
+
+    pub fn g(x: Ordering) {
+        match x {
+            Ordering::Relaxed => println!("relaxed"),
+            Ordering::Release => println!("release"),
+            Ordering::Acquire => println!("acquire"),
+            //~^ ERROR: this match arm has an identical body to the `_` wildcard arm
+            _ => repeat(),
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
index 5c277f9..e5066393 100644
--- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
@@ -1,7 +1,6 @@
 #![feature(non_exhaustive_omitted_patterns_lint)]
 #![warn(clippy::match_same_arms)]
 #![no_main]
-//@no-rustfix
 use std::sync::atomic::Ordering; // #[non_exhaustive] enum
 
 fn repeat() -> ! {
diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
index cf2a753..aa7f8c9 100644
--- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
@@ -1,12 +1,13 @@
 error: this match arm has an identical body to the `_` wildcard arm
-  --> tests/ui/match_same_arms_non_exhaustive.rs:45:9
+  --> tests/ui/match_same_arms_non_exhaustive.rs:44:9
    |
-LL |         Ordering::AcqRel | Ordering::SeqCst => repeat(),
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try removing the arm
+LL | /         Ordering::AcqRel | Ordering::SeqCst => repeat(),
+LL | |
+   | |________^ help: try removing the arm
    |
    = help: or try changing either arm body
 note: `_` wildcard arm here
-  --> tests/ui/match_same_arms_non_exhaustive.rs:47:9
+  --> tests/ui/match_same_arms_non_exhaustive.rs:46:9
    |
 LL |         _ => repeat(),
    |         ^^^^^^^^^^^^^
@@ -14,14 +15,15 @@
    = help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]`
 
 error: this match arm has an identical body to the `_` wildcard arm
-  --> tests/ui/match_same_arms_non_exhaustive.rs:59:13
+  --> tests/ui/match_same_arms_non_exhaustive.rs:58:13
    |
-LL |             Ordering::AcqRel | Ordering::SeqCst => repeat(),
-   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try removing the arm
+LL | /             Ordering::AcqRel | Ordering::SeqCst => repeat(),
+LL | |
+   | |____________^ help: try removing the arm
    |
    = help: or try changing either arm body
 note: `_` wildcard arm here
-  --> tests/ui/match_same_arms_non_exhaustive.rs:61:13
+  --> tests/ui/match_same_arms_non_exhaustive.rs:60:13
    |
 LL |             _ => repeat(),
    |             ^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
index d026e00..2750e0c 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs
@@ -161,7 +161,23 @@
     f: u32,
 }
 
-// Do not lint because accessing union fields from const functions is unstable
+// Do not lint because accessing union fields from const functions is unstable in 1.55
+#[clippy::msrv = "1.55"]
 fn h(u: U) -> u32 {
     unsafe { u.f }
 }
+
+mod msrv {
+    struct Foo(*const u8, *mut u8);
+
+    impl Foo {
+        #[clippy::msrv = "1.57"]
+        fn deref_ptr_cannot_be_const(self) -> usize {
+            unsafe { *self.0 as usize }
+        }
+        #[clippy::msrv = "1.58"]
+        fn deref_mut_ptr_cannot_be_const(self) -> usize {
+            unsafe { *self.1 as usize }
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
index 12a8320..06dbbeb 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.rs
@@ -113,3 +113,31 @@
 // Lint this, since it can be dropped in const contexts
 // FIXME(effects)
 fn d(this: D) {}
+
+mod msrv {
+    struct Foo(*const u8, &'static u8);
+
+    impl Foo {
+        #[clippy::msrv = "1.58"]
+        fn deref_ptr_can_be_const(self) -> usize {
+            //~^ ERROR: this could be a `const fn`
+            unsafe { *self.0 as usize }
+        }
+
+        fn deref_copied_val(self) -> usize {
+            //~^ ERROR: this could be a `const fn`
+            *self.1 as usize
+        }
+    }
+
+    union Bar {
+        val: u8,
+    }
+
+    #[clippy::msrv = "1.56"]
+    fn union_access_can_be_const() {
+        //~^ ERROR: this could be a `const fn`
+        let bar = Bar { val: 1 };
+        let _ = unsafe { bar.val };
+    }
+}
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
index 082459f..b2cade3 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/could_be_const.stderr
@@ -102,5 +102,33 @@
 LL | | }
    | |_^
 
-error: aborting due to 11 previous errors
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:122:9
+   |
+LL | /         fn deref_ptr_can_be_const(self) -> usize {
+LL | |
+LL | |             unsafe { *self.0 as usize }
+LL | |         }
+   | |_________^
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:127:9
+   |
+LL | /         fn deref_copied_val(self) -> usize {
+LL | |
+LL | |             *self.1 as usize
+LL | |         }
+   | |_________^
+
+error: this could be a `const fn`
+  --> tests/ui/missing_const_for_fn/could_be_const.rs:138:5
+   |
+LL | /     fn union_access_can_be_const() {
+LL | |
+LL | |         let bar = Bar { val: 1 };
+LL | |         let _ = unsafe { bar.val };
+LL | |     }
+   | |_____^
+
+error: aborting due to 14 previous errors
 
diff --git a/src/tools/clippy/tests/ui/missing_panics_doc.rs b/src/tools/clippy/tests/ui/missing_panics_doc.rs
index 0e1533f..b0fa8e9 100644
--- a/src/tools/clippy/tests/ui/missing_panics_doc.rs
+++ b/src/tools/clippy/tests/ui/missing_panics_doc.rs
@@ -191,3 +191,11 @@
     // Not here.
     some_macro_that_panics!()
 }
+
+pub fn issue_12760<const N: usize>() {
+    const {
+        if N == 0 {
+            panic!();
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed
index bd7a9a0..5478372 100644
--- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed
+++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.fixed
@@ -141,8 +141,8 @@
         let f = |arg| {
             let loc = "loc".to_owned();
             let _ = std::fs::write("x", &env); // Don't lint. In environment
-            let _ = std::fs::write("x", arg);
-            let _ = std::fs::write("x", loc);
+            let _ = std::fs::write("x", &arg);
+            let _ = std::fs::write("x", &loc);
         };
         let _ = std::fs::write("x", &env); // Don't lint. Borrowed by `f`
         f(arg);
@@ -158,13 +158,13 @@
         fn f(_: impl Debug) {}
 
         let x = X;
-        f(&x); // Don't lint. Has significant drop
+        f(&x); // Don't lint, not copy, passed by a reference to a variable
     }
     {
         fn f(_: impl AsRef<str>) {}
 
         let x = String::new();
-        f(x);
+        f(&x);
     }
     {
         fn f(_: impl AsRef<str>) {}
@@ -299,4 +299,38 @@
             check_str(&owner.0); // Don't lint. `owner` can't be partially moved because it impl Drop
         }
     }
+    {
+        #[derive(Debug)]
+        struct X(Vec<u8>);
+
+        fn f(_: impl Debug) {}
+
+        let x = X(vec![]);
+        f(&x); // Don't lint, makes x unavailable later
+    }
+    {
+        #[derive(Debug)]
+        struct X;
+
+        impl Drop for X {
+            fn drop(&mut self) {}
+        }
+
+        fn f(_: impl Debug) {}
+
+        #[derive(Debug)]
+        struct Y(X);
+
+        let y = Y(X);
+        f(&y); // Don't lint. Not copy, passed by a reference to value
+    }
+    {
+        fn f(_: impl AsRef<str>) {}
+        let x = String::new();
+        f(&x); // Don't lint, not a copy, makes it unavailable later
+        f(String::new()); // Lint, makes no difference
+        let y = "".to_owned();
+        f(&y); // Don't lint
+        f("".to_owned()); // Lint
+    }
 }
diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs
index 5cfd4ce..2643815 100644
--- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.rs
@@ -158,7 +158,7 @@
         fn f(_: impl Debug) {}
 
         let x = X;
-        f(&x); // Don't lint. Has significant drop
+        f(&x); // Don't lint, not copy, passed by a reference to a variable
     }
     {
         fn f(_: impl AsRef<str>) {}
@@ -299,4 +299,38 @@
             check_str(&owner.0); // Don't lint. `owner` can't be partially moved because it impl Drop
         }
     }
+    {
+        #[derive(Debug)]
+        struct X(Vec<u8>);
+
+        fn f(_: impl Debug) {}
+
+        let x = X(vec![]);
+        f(&x); // Don't lint, makes x unavailable later
+    }
+    {
+        #[derive(Debug)]
+        struct X;
+
+        impl Drop for X {
+            fn drop(&mut self) {}
+        }
+
+        fn f(_: impl Debug) {}
+
+        #[derive(Debug)]
+        struct Y(X);
+
+        let y = Y(X);
+        f(&y); // Don't lint. Not copy, passed by a reference to value
+    }
+    {
+        fn f(_: impl AsRef<str>) {}
+        let x = String::new();
+        f(&x); // Don't lint, not a copy, makes it unavailable later
+        f(&String::new()); // Lint, makes no difference
+        let y = "".to_owned();
+        f(&y); // Don't lint
+        f(&"".to_owned()); // Lint
+    }
 }
diff --git a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr
index 83c076f..fba0755 100644
--- a/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr
+++ b/src/tools/clippy/tests/ui/needless_borrows_for_generic_args.stderr
@@ -50,28 +50,22 @@
    |                                         ^^^^^^^^^^^^^ help: change this to: `["-a", "-l"]`
 
 error: the borrowed expression implements the required traits
-  --> tests/ui/needless_borrows_for_generic_args.rs:144:41
-   |
-LL |             let _ = std::fs::write("x", &arg);
-   |                                         ^^^^ help: change this to: `arg`
-
-error: the borrowed expression implements the required traits
-  --> tests/ui/needless_borrows_for_generic_args.rs:145:41
-   |
-LL |             let _ = std::fs::write("x", &loc);
-   |                                         ^^^^ help: change this to: `loc`
-
-error: the borrowed expression implements the required traits
-  --> tests/ui/needless_borrows_for_generic_args.rs:167:11
-   |
-LL |         f(&x);
-   |           ^^ help: change this to: `x`
-
-error: the borrowed expression implements the required traits
   --> tests/ui/needless_borrows_for_generic_args.rs:247:13
    |
 LL |         foo(&a);
    |             ^^ help: change this to: `a`
 
-error: aborting due to 12 previous errors
+error: the borrowed expression implements the required traits
+  --> tests/ui/needless_borrows_for_generic_args.rs:331:11
+   |
+LL |         f(&String::new()); // Lint, makes no difference
+   |           ^^^^^^^^^^^^^^ help: change this to: `String::new()`
+
+error: the borrowed expression implements the required traits
+  --> tests/ui/needless_borrows_for_generic_args.rs:334:11
+   |
+LL |         f(&"".to_owned()); // Lint
+   |           ^^^^^^^^^^^^^^ help: change this to: `"".to_owned()`
+
+error: aborting due to 11 previous errors
 
diff --git a/src/tools/clippy/tests/ui/needless_late_init.stderr b/src/tools/clippy/tests/ui/needless_late_init.stderr
index 1695784..ce64861 100644
--- a/src/tools/clippy/tests/ui/needless_late_init.stderr
+++ b/src/tools/clippy/tests/ui/needless_late_init.stderr
@@ -8,10 +8,11 @@
    |
    = note: `-D clippy::needless-late-init` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::needless_late_init)]`
-help: declare `a` here
+help: move the declaration `a` here
    |
-LL |     let a = "zero";
-   |     ~~~~~
+LL ~     
+LL ~     let a = "zero";
+   |
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:30:5
@@ -22,10 +23,12 @@
 LL |     b = 1;
    |     ^^^^^ initialised here
    |
-help: declare `b` here
+help: move the declaration `b` here
    |
-LL |     let b = 1;
-   |     ~~~~~
+LL ~     
+LL |     let c;
+LL ~     let b = 1;
+   |
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:31:5
@@ -36,10 +39,12 @@
 LL |     c = 2;
    |     ^^^^^ initialised here
    |
-help: declare `c` here
+help: move the declaration `c` here
    |
-LL |     let c = 2;
-   |     ~~~~~
+LL ~     
+LL |     b = 1;
+LL ~     let c = 2;
+   |
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:35:5
@@ -49,10 +54,11 @@
 LL |     d = 1;
    |     ^^^^^ initialised here
    |
-help: declare `d` here
+help: move the declaration `d` here
    |
-LL |     let d: usize = 1;
-   |     ~~~~~~~~~~~~
+LL ~     
+LL ~     let d: usize = 1;
+   |
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:38:5
@@ -62,10 +68,11 @@
 LL |     e = format!("{}", d);
    |     ^^^^^^^^^^^^^^^^^^^^ initialised here
    |
-help: declare `e` here
+help: move the declaration `e` here
    |
-LL |     let e = format!("{}", d);
-   |     ~~~~~
+LL ~     
+LL ~     let e = format!("{}", d);
+   |
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:43:5
@@ -73,20 +80,17 @@
 LL |     let a;
    |     ^^^^^^
    |
-help: declare `a` here
+help: move the declaration `a` here and remove the assignments from the `match` arms
    |
-LL |     let a = match n {
-   |     +++++++
-help: remove the assignments from the `match` arms
-   |
+LL ~     
+LL |     let n = 1;
+LL ~     let a = match n {
 LL ~         1 => "one",
 LL |         _ => {
 LL ~             "two"
+LL |         },
+LL ~     };
    |
-help: add a semicolon after the `match` expression
-   |
-LL |     };
-   |      +
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:52:5
@@ -94,20 +98,15 @@
 LL |     let b;
    |     ^^^^^^
    |
-help: declare `b` here
+help: move the declaration `b` here and remove the assignments from the branches
    |
-LL |     let b = if n == 3 {
-   |     +++++++
-help: remove the assignments from the branches
-   |
+LL ~     
+LL ~     let b = if n == 3 {
 LL ~         "four"
 LL |     } else {
 LL ~         "five"
+LL ~     };
    |
-help: add a semicolon after the `if` expression
-   |
-LL |     };
-   |      +
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:59:5
@@ -115,20 +114,16 @@
 LL |     let d;
    |     ^^^^^^
    |
-help: declare `d` here
+help: move the declaration `d` here and remove the assignments from the branches
    |
-LL |     let d = if true {
-   |     +++++++
-help: remove the assignments from the branches
-   |
+LL ~     
+LL ~     let d = if true {
+LL |         let temp = 5;
 LL ~         temp
 LL |     } else {
 LL ~         15
+LL ~     };
    |
-help: add a semicolon after the `if` expression
-   |
-LL |     };
-   |      +
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:67:5
@@ -136,20 +131,15 @@
 LL |     let e;
    |     ^^^^^^
    |
-help: declare `e` here
+help: move the declaration `e` here and remove the assignments from the branches
    |
-LL |     let e = if true {
-   |     +++++++
-help: remove the assignments from the branches
-   |
+LL ~     
+LL ~     let e = if true {
 LL ~         format!("{} {}", a, b)
 LL |     } else {
 LL ~         format!("{}", n)
+LL ~     };
    |
-help: add a semicolon after the `if` expression
-   |
-LL |     };
-   |      +
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:74:5
@@ -157,14 +147,11 @@
 LL |     let f;
    |     ^^^^^^
    |
-help: declare `f` here
+help: move the declaration `f` here and remove the assignments from the `match` arms
    |
-LL |     let f = match 1 {
-   |     +++++++
-help: remove the assignments from the `match` arms
-   |
-LL -         1 => f = "three",
-LL +         1 => "three",
+LL ~     
+LL ~     let f = match 1 {
+LL ~         1 => "three",
    |
 
 error: unneeded late initialization
@@ -173,19 +160,15 @@
 LL |     let g: usize;
    |     ^^^^^^^^^^^^^
    |
-help: declare `g` here
+help: move the declaration `g` here and remove the assignments from the branches
    |
-LL |     let g: usize = if true {
-   |     ++++++++++++++
-help: remove the assignments from the branches
+LL ~     
+LL ~     let g: usize = if true {
+LL ~         5
+LL |     } else {
+LL |         panic!();
+LL ~     };
    |
-LL -         g = 5;
-LL +         5
-   |
-help: add a semicolon after the `if` expression
-   |
-LL |     };
-   |      +
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:88:5
@@ -196,10 +179,12 @@
 LL |     x = 1;
    |     ^^^^^ initialised here
    |
-help: declare `x` here
+help: move the declaration `x` here
    |
-LL |     let x = 1;
-   |     ~~~~~
+LL ~     
+LL |     let y = SignificantDrop;
+LL ~     let x = 1;
+   |
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:92:5
@@ -210,10 +195,12 @@
 LL |     x = SignificantDrop;
    |     ^^^^^^^^^^^^^^^^^^^ initialised here
    |
-help: declare `x` here
+help: move the declaration `x` here
    |
-LL |     let x = SignificantDrop;
-   |     ~~~~~
+LL ~     
+LL |     let y = 1;
+LL ~     let x = SignificantDrop;
+   |
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:96:5
@@ -224,10 +211,14 @@
 LL |     x = SignificantDrop;
    |     ^^^^^^^^^^^^^^^^^^^ initialised here
    |
-help: declare `x` here
+help: move the declaration `x` here
    |
-LL |     let x = SignificantDrop;
-   |     ~~~~~
+LL ~     
+LL |     // types that should be considered insignificant
+ ...
+LL |     let y = Box::new(4);
+LL ~     let x = SignificantDrop;
+   |
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:115:5
@@ -235,20 +226,17 @@
 LL |     let a;
    |     ^^^^^^
    |
-help: declare `a` here
+help: move the declaration `a` here and remove the assignments from the `match` arms
    |
-LL |     let a = match n {
-   |     +++++++
-help: remove the assignments from the `match` arms
-   |
+LL ~     
+LL |     let n = 1;
+LL ~     let a = match n {
 LL ~         1 => f().await,
 LL |         _ => {
 LL ~             "two"
+LL |         },
+LL ~     };
    |
-help: add a semicolon after the `match` expression
-   |
-LL |     };
-   |      +
 
 error: unneeded late initialization
   --> tests/ui/needless_late_init.rs:132:5
@@ -256,20 +244,17 @@
 LL |     let a;
    |     ^^^^^^
    |
-help: declare `a` here
+help: move the declaration `a` here and remove the assignments from the `match` arms
    |
-LL |     let a = match n {
-   |     +++++++
-help: remove the assignments from the `match` arms
-   |
+LL ~     
+LL |     let n = 1;
+LL ~     let a = match n {
 LL ~         1 => f(),
 LL |         _ => {
 LL ~             "two"
+LL |         },
+LL ~     };
    |
-help: add a semicolon after the `match` expression
-   |
-LL |     };
-   |      +
 
 error: aborting due to 16 previous errors
 
diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs
index dabeda7..0ea911c 100644
--- a/src/tools/clippy/tests/ui/no_effect.rs
+++ b/src/tools/clippy/tests/ui/no_effect.rs
@@ -1,6 +1,5 @@
 #![feature(fn_traits, unboxed_closures)]
 #![warn(clippy::no_effect_underscore_binding)]
-#![allow(dead_code, path_statements)]
 #![allow(
     clippy::deref_addrof,
     clippy::redundant_field_names,
@@ -33,7 +32,6 @@
     }
 }
 
-struct Unit;
 struct Tuple(i32);
 struct Struct {
     field: i32,
@@ -42,10 +40,6 @@
     Tuple(i32),
     Struct { field: i32 },
 }
-struct DropUnit;
-impl Drop for DropUnit {
-    fn drop(&mut self) {}
-}
 struct DropStruct {
     field: i32,
 }
@@ -117,15 +111,9 @@
 
 fn main() {
     let s = get_struct();
-    let s2 = get_struct();
 
     0;
     //~^ ERROR: statement with no effect
-    //~| NOTE: `-D clippy::no-effect` implied by `-D warnings`
-    s2;
-    //~^ ERROR: statement with no effect
-    Unit;
-    //~^ ERROR: statement with no effect
     Tuple(0);
     //~^ ERROR: statement with no effect
     Struct { field: 0 };
@@ -192,7 +180,6 @@
     unsafe { unsafe_fn() };
     let _used = get_struct();
     let _x = vec![1];
-    DropUnit;
     DropStruct { field: 0 };
     DropTuple(0);
     DropEnum::Tuple(0);
diff --git a/src/tools/clippy/tests/ui/no_effect.stderr b/src/tools/clippy/tests/ui/no_effect.stderr
index c7c8eec..48ec997 100644
--- a/src/tools/clippy/tests/ui/no_effect.stderr
+++ b/src/tools/clippy/tests/ui/no_effect.stderr
@@ -1,5 +1,5 @@
 error: statement with no effect
-  --> tests/ui/no_effect.rs:122:5
+  --> tests/ui/no_effect.rs:115:5
    |
 LL |     0;
    |     ^^
@@ -8,151 +8,139 @@
    = help: to override `-D warnings` add `#[allow(clippy::no_effect)]`
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:125:5
-   |
-LL |     s2;
-   |     ^^^
-
-error: statement with no effect
-  --> tests/ui/no_effect.rs:127:5
-   |
-LL |     Unit;
-   |     ^^^^^
-
-error: statement with no effect
-  --> tests/ui/no_effect.rs:129:5
+  --> tests/ui/no_effect.rs:117:5
    |
 LL |     Tuple(0);
    |     ^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:131:5
+  --> tests/ui/no_effect.rs:119:5
    |
 LL |     Struct { field: 0 };
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:133:5
+  --> tests/ui/no_effect.rs:121:5
    |
 LL |     Struct { ..s };
    |     ^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:135:5
+  --> tests/ui/no_effect.rs:123:5
    |
 LL |     Union { a: 0 };
    |     ^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:137:5
+  --> tests/ui/no_effect.rs:125:5
    |
 LL |     Enum::Tuple(0);
    |     ^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:139:5
+  --> tests/ui/no_effect.rs:127:5
    |
 LL |     Enum::Struct { field: 0 };
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:141:5
+  --> tests/ui/no_effect.rs:129:5
    |
 LL |     5 + 6;
    |     ^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:143:5
+  --> tests/ui/no_effect.rs:131:5
    |
 LL |     *&42;
    |     ^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:145:5
+  --> tests/ui/no_effect.rs:133:5
    |
 LL |     &6;
    |     ^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:147:5
+  --> tests/ui/no_effect.rs:135:5
    |
 LL |     (5, 6, 7);
    |     ^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:149:5
+  --> tests/ui/no_effect.rs:137:5
    |
 LL |     ..;
    |     ^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:151:5
+  --> tests/ui/no_effect.rs:139:5
    |
 LL |     5..;
    |     ^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:153:5
+  --> tests/ui/no_effect.rs:141:5
    |
 LL |     ..5;
    |     ^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:155:5
+  --> tests/ui/no_effect.rs:143:5
    |
 LL |     5..6;
    |     ^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:157:5
+  --> tests/ui/no_effect.rs:145:5
    |
 LL |     5..=6;
    |     ^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:159:5
+  --> tests/ui/no_effect.rs:147:5
    |
 LL |     [42, 55];
    |     ^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:161:5
+  --> tests/ui/no_effect.rs:149:5
    |
 LL |     [42, 55][1];
    |     ^^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:163:5
+  --> tests/ui/no_effect.rs:151:5
    |
 LL |     (42, 55).1;
    |     ^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:165:5
+  --> tests/ui/no_effect.rs:153:5
    |
 LL |     [42; 55];
    |     ^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:167:5
+  --> tests/ui/no_effect.rs:155:5
    |
 LL |     [42; 55][13];
    |     ^^^^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:170:5
+  --> tests/ui/no_effect.rs:158:5
    |
 LL |     || x += 5;
    |     ^^^^^^^^^^
 
 error: statement with no effect
-  --> tests/ui/no_effect.rs:173:5
+  --> tests/ui/no_effect.rs:161:5
    |
 LL |     FooString { s: s };
    |     ^^^^^^^^^^^^^^^^^^^
 
 error: binding to `_` prefixed variable with no side-effect
-  --> tests/ui/no_effect.rs:175:9
+  --> tests/ui/no_effect.rs:163:9
    |
 LL |     let _unused = 1;
    |         ^^^^^^^
@@ -161,22 +149,22 @@
    = help: to override `-D warnings` add `#[allow(clippy::no_effect_underscore_binding)]`
 
 error: binding to `_` prefixed variable with no side-effect
-  --> tests/ui/no_effect.rs:178:9
+  --> tests/ui/no_effect.rs:166:9
    |
 LL |     let _penguin = || println!("Some helpful closure");
    |         ^^^^^^^^
 
 error: binding to `_` prefixed variable with no side-effect
-  --> tests/ui/no_effect.rs:180:9
+  --> tests/ui/no_effect.rs:168:9
    |
 LL |     let _duck = Struct { field: 0 };
    |         ^^^^^
 
 error: binding to `_` prefixed variable with no side-effect
-  --> tests/ui/no_effect.rs:182:9
+  --> tests/ui/no_effect.rs:170:9
    |
 LL |     let _cat = [2, 4, 6, 8][2];
    |         ^^^^
 
-error: aborting due to 29 previous errors
+error: aborting due to 27 previous errors
 
diff --git a/src/tools/clippy/tests/ui/ptr_arg.rs b/src/tools/clippy/tests/ui/ptr_arg.rs
index fcd716f..5d6e488 100644
--- a/src/tools/clippy/tests/ui/ptr_arg.rs
+++ b/src/tools/clippy/tests/ui/ptr_arg.rs
@@ -282,7 +282,7 @@
         todo!()
     }
 
-    // These two's return types don't use use 'a so it's not okay
+    // These two's return types don't use 'a so it's not okay
     fn cow_bad_ret_ty_1<'a>(input: &'a Cow<'a, str>) -> &'static str {
         //~^ ERROR: using a reference to `Cow` is not recommended
         todo!()
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
index 0305d89..7fc89bb 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs
@@ -675,4 +675,60 @@
     }
 }
 
+// https://github.com/rust-lang/rust-clippy/issues/9072
+fn should_not_trigger_lint_if_place_expr_has_significant_drop() {
+    let x = Mutex::new(vec![1, 2, 3]);
+    let x_guard = x.lock().unwrap();
+
+    match x_guard[0] {
+        1 => println!("1!"),
+        x => println!("{x}"),
+    }
+
+    match x_guard.len() {
+        1 => println!("1!"),
+        x => println!("{x}"),
+    }
+}
+
+struct Guard<'a, T>(MutexGuard<'a, T>);
+
+struct Ref<'a, T>(&'a T);
+
+impl<'a, T> Guard<'a, T> {
+    fn guard(&self) -> &MutexGuard<T> {
+        &self.0
+    }
+
+    fn guard_ref(&self) -> Ref<MutexGuard<T>> {
+        Ref(&self.0)
+    }
+
+    fn take(self) -> Box<MutexGuard<'a, T>> {
+        Box::new(self.0)
+    }
+}
+
+fn should_not_trigger_for_significant_drop_ref() {
+    let mutex = Mutex::new(vec![1, 2]);
+    let guard = Guard(mutex.lock().unwrap());
+
+    match guard.guard().len() {
+        0 => println!("empty"),
+        _ => println!("not empty"),
+    }
+
+    match guard.guard_ref().0.len() {
+        0 => println!("empty"),
+        _ => println!("not empty"),
+    }
+
+    match guard.take().len() {
+        //~^ ERROR: temporary with significant `Drop` in `match` scrutinee will live until the
+        //~| NOTE: this might lead to deadlocks or other unexpected behavior
+        0 => println!("empty"),
+        _ => println!("not empty"),
+    };
+}
+
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
index 7d5b1ac..811bb06 100644
--- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
+++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.stderr
@@ -28,6 +28,9 @@
 LL |             println!("{}", s.lock_m().get_the_value());
    |                            ---------- another value with significant `Drop` created here
 ...
+LL |             println!("{}", s.lock_m().get_the_value());
+   |                            ---------- another value with significant `Drop` created here
+...
 LL |     }
    |      - temporary lives until here
    |
@@ -47,6 +50,9 @@
 LL |             println!("{}", s.lock_m().get_the_value());
    |                            ---------- another value with significant `Drop` created here
 ...
+LL |             println!("{}", s.lock_m().get_the_value());
+   |                            ---------- another value with significant `Drop` created here
+...
 LL |     }
    |      - temporary lives until here
    |
@@ -360,7 +366,7 @@
    |           ^^^^^^^^^^^^^^^^^^^^^^^^
 ...
 LL |         _ => println!("Value is {}", s.lock().deref()),
-   |                                      ---------------- another value with significant `Drop` created here
+   |                                      -------- another value with significant `Drop` created here
 LL |     };
    |      - temporary lives until here
    |
@@ -378,7 +384,7 @@
    |           ^^^^^^^^^^^^^^^^^^^^^^^^
 ...
 LL |         matcher => println!("Value is {}", s.lock().deref()),
-   |                                            ---------------- another value with significant `Drop` created here
+   |                                            -------- another value with significant `Drop` created here
 LL |         _ => println!("Value was not a match"),
 LL |     };
    |      - temporary lives until here
@@ -499,5 +505,21 @@
 LL ~     match value {
    |
 
-error: aborting due to 26 previous errors
+error: temporary with significant `Drop` in `match` scrutinee will live until the end of the `match` expression
+  --> tests/ui/significant_drop_in_scrutinee.rs:726:11
+   |
+LL |     match guard.take().len() {
+   |           ^^^^^^^^^^^^^^^^^^
+...
+LL |     };
+   |      - temporary lives until here
+   |
+   = note: this might lead to deadlocks or other unexpected behavior
+help: try moving the temporary above the match
+   |
+LL ~     let value = guard.take().len();
+LL ~     match value {
+   |
+
+error: aborting due to 27 previous errors
 
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed
index fe8db3d..1a48051 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed
+++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.fixed
@@ -1,7 +1,7 @@
 #![warn(clippy::transmute_int_to_non_zero)]
 #![allow(clippy::missing_transmute_annotations)]
 
-use core::num::*;
+use core::num::NonZero;
 
 fn main() {
     let int_u8: u8 = 1;
@@ -16,38 +16,38 @@
     let int_i64: i64 = 1;
     let int_i128: i128 = 1;
 
-    let _: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(int_u8) };
-    //~^ ERROR: transmute from a `u8` to a `NonZeroU8`
+    let _: NonZero<u8> = unsafe { NonZero::new_unchecked(int_u8) };
+    //~^ ERROR: transmute from a `u8` to a `NonZero<u8>`
     //~| NOTE: `-D clippy::transmute-int-to-non-zero` implied by `-D warnings`
-    let _: NonZeroU16 = unsafe { NonZeroU16::new_unchecked(int_u16) };
-    //~^ ERROR: transmute from a `u16` to a `NonZeroU16`
-    let _: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(int_u32) };
-    //~^ ERROR: transmute from a `u32` to a `NonZeroU32`
-    let _: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(int_u64) };
-    //~^ ERROR: transmute from a `u64` to a `NonZeroU64`
-    let _: NonZeroU128 = unsafe { NonZeroU128::new_unchecked(int_u128) };
-    //~^ ERROR: transmute from a `u128` to a `NonZeroU128`
+    let _: NonZero<u16> = unsafe { NonZero::new_unchecked(int_u16) };
+    //~^ ERROR: transmute from a `u16` to a `NonZero<u16>`
+    let _: NonZero<u32> = unsafe { NonZero::new_unchecked(int_u32) };
+    //~^ ERROR: transmute from a `u32` to a `NonZero<u32>`
+    let _: NonZero<u64> = unsafe { NonZero::new_unchecked(int_u64) };
+    //~^ ERROR: transmute from a `u64` to a `NonZero<u64>`
+    let _: NonZero<u128> = unsafe { NonZero::new_unchecked(int_u128) };
+    //~^ ERROR: transmute from a `u128` to a `NonZero<u128>`
 
-    let _: NonZeroI8 = unsafe { NonZeroI8::new_unchecked(int_i8) };
-    //~^ ERROR: transmute from a `i8` to a `NonZeroI8`
-    let _: NonZeroI16 = unsafe { NonZeroI16::new_unchecked(int_i16) };
-    //~^ ERROR: transmute from a `i16` to a `NonZeroI16`
-    let _: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(int_i32) };
-    //~^ ERROR: transmute from a `i32` to a `NonZeroI32`
-    let _: NonZeroI64 = unsafe { NonZeroI64::new_unchecked(int_i64) };
-    //~^ ERROR: transmute from a `i64` to a `NonZeroI64`
-    let _: NonZeroI128 = unsafe { NonZeroI128::new_unchecked(int_i128) };
-    //~^ ERROR: transmute from a `i128` to a `NonZeroI128`
+    let _: NonZero<i8> = unsafe { NonZero::new_unchecked(int_i8) };
+    //~^ ERROR: transmute from a `i8` to a `NonZero<i8>`
+    let _: NonZero<i16> = unsafe { NonZero::new_unchecked(int_i16) };
+    //~^ ERROR: transmute from a `i16` to a `NonZero<i16>`
+    let _: NonZero<i32> = unsafe { NonZero::new_unchecked(int_i32) };
+    //~^ ERROR: transmute from a `i32` to a `NonZero<i32>`
+    let _: NonZero<i64> = unsafe { NonZero::new_unchecked(int_i64) };
+    //~^ ERROR: transmute from a `i64` to a `NonZero<i64>`
+    let _: NonZero<i128> = unsafe { NonZero::new_unchecked(int_i128) };
+    //~^ ERROR: transmute from a `i128` to a `NonZero<i128>`
 
-    let _: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(int_u8) };
-    let _: NonZeroU16 = unsafe { NonZeroU16::new_unchecked(int_u16) };
-    let _: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(int_u32) };
-    let _: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(int_u64) };
-    let _: NonZeroU128 = unsafe { NonZeroU128::new_unchecked(int_u128) };
+    let _: NonZero<u8> = unsafe { NonZero::new_unchecked(int_u8) };
+    let _: NonZero<u16> = unsafe { NonZero::new_unchecked(int_u16) };
+    let _: NonZero<u32> = unsafe { NonZero::new_unchecked(int_u32) };
+    let _: NonZero<u64> = unsafe { NonZero::new_unchecked(int_u64) };
+    let _: NonZero<u128> = unsafe { NonZero::new_unchecked(int_u128) };
 
-    let _: NonZeroI8 = unsafe { NonZeroI8::new_unchecked(int_i8) };
-    let _: NonZeroI16 = unsafe { NonZeroI16::new_unchecked(int_i16) };
-    let _: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(int_i32) };
-    let _: NonZeroI64 = unsafe { NonZeroI64::new_unchecked(int_i64) };
-    let _: NonZeroI128 = unsafe { NonZeroI128::new_unchecked(int_i128) };
+    let _: NonZero<i8> = unsafe { NonZero::new_unchecked(int_i8) };
+    let _: NonZero<i16> = unsafe { NonZero::new_unchecked(int_i16) };
+    let _: NonZero<i32> = unsafe { NonZero::new_unchecked(int_i32) };
+    let _: NonZero<i64> = unsafe { NonZero::new_unchecked(int_i64) };
+    let _: NonZero<i128> = unsafe { NonZero::new_unchecked(int_i128) };
 }
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs
index a79ed52..d8e842f 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs
+++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.rs
@@ -1,7 +1,7 @@
 #![warn(clippy::transmute_int_to_non_zero)]
 #![allow(clippy::missing_transmute_annotations)]
 
-use core::num::*;
+use core::num::NonZero;
 
 fn main() {
     let int_u8: u8 = 1;
@@ -16,38 +16,38 @@
     let int_i64: i64 = 1;
     let int_i128: i128 = 1;
 
-    let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) };
-    //~^ ERROR: transmute from a `u8` to a `NonZeroU8`
+    let _: NonZero<u8> = unsafe { std::mem::transmute(int_u8) };
+    //~^ ERROR: transmute from a `u8` to a `NonZero<u8>`
     //~| NOTE: `-D clippy::transmute-int-to-non-zero` implied by `-D warnings`
-    let _: NonZeroU16 = unsafe { std::mem::transmute(int_u16) };
-    //~^ ERROR: transmute from a `u16` to a `NonZeroU16`
-    let _: NonZeroU32 = unsafe { std::mem::transmute(int_u32) };
-    //~^ ERROR: transmute from a `u32` to a `NonZeroU32`
-    let _: NonZeroU64 = unsafe { std::mem::transmute(int_u64) };
-    //~^ ERROR: transmute from a `u64` to a `NonZeroU64`
-    let _: NonZeroU128 = unsafe { std::mem::transmute(int_u128) };
-    //~^ ERROR: transmute from a `u128` to a `NonZeroU128`
+    let _: NonZero<u16> = unsafe { std::mem::transmute(int_u16) };
+    //~^ ERROR: transmute from a `u16` to a `NonZero<u16>`
+    let _: NonZero<u32> = unsafe { std::mem::transmute(int_u32) };
+    //~^ ERROR: transmute from a `u32` to a `NonZero<u32>`
+    let _: NonZero<u64> = unsafe { std::mem::transmute(int_u64) };
+    //~^ ERROR: transmute from a `u64` to a `NonZero<u64>`
+    let _: NonZero<u128> = unsafe { std::mem::transmute(int_u128) };
+    //~^ ERROR: transmute from a `u128` to a `NonZero<u128>`
 
-    let _: NonZeroI8 = unsafe { std::mem::transmute(int_i8) };
-    //~^ ERROR: transmute from a `i8` to a `NonZeroI8`
-    let _: NonZeroI16 = unsafe { std::mem::transmute(int_i16) };
-    //~^ ERROR: transmute from a `i16` to a `NonZeroI16`
-    let _: NonZeroI32 = unsafe { std::mem::transmute(int_i32) };
-    //~^ ERROR: transmute from a `i32` to a `NonZeroI32`
-    let _: NonZeroI64 = unsafe { std::mem::transmute(int_i64) };
-    //~^ ERROR: transmute from a `i64` to a `NonZeroI64`
-    let _: NonZeroI128 = unsafe { std::mem::transmute(int_i128) };
-    //~^ ERROR: transmute from a `i128` to a `NonZeroI128`
+    let _: NonZero<i8> = unsafe { std::mem::transmute(int_i8) };
+    //~^ ERROR: transmute from a `i8` to a `NonZero<i8>`
+    let _: NonZero<i16> = unsafe { std::mem::transmute(int_i16) };
+    //~^ ERROR: transmute from a `i16` to a `NonZero<i16>`
+    let _: NonZero<i32> = unsafe { std::mem::transmute(int_i32) };
+    //~^ ERROR: transmute from a `i32` to a `NonZero<i32>`
+    let _: NonZero<i64> = unsafe { std::mem::transmute(int_i64) };
+    //~^ ERROR: transmute from a `i64` to a `NonZero<i64>`
+    let _: NonZero<i128> = unsafe { std::mem::transmute(int_i128) };
+    //~^ ERROR: transmute from a `i128` to a `NonZero<i128>`
 
-    let _: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(int_u8) };
-    let _: NonZeroU16 = unsafe { NonZeroU16::new_unchecked(int_u16) };
-    let _: NonZeroU32 = unsafe { NonZeroU32::new_unchecked(int_u32) };
-    let _: NonZeroU64 = unsafe { NonZeroU64::new_unchecked(int_u64) };
-    let _: NonZeroU128 = unsafe { NonZeroU128::new_unchecked(int_u128) };
+    let _: NonZero<u8> = unsafe { NonZero::new_unchecked(int_u8) };
+    let _: NonZero<u16> = unsafe { NonZero::new_unchecked(int_u16) };
+    let _: NonZero<u32> = unsafe { NonZero::new_unchecked(int_u32) };
+    let _: NonZero<u64> = unsafe { NonZero::new_unchecked(int_u64) };
+    let _: NonZero<u128> = unsafe { NonZero::new_unchecked(int_u128) };
 
-    let _: NonZeroI8 = unsafe { NonZeroI8::new_unchecked(int_i8) };
-    let _: NonZeroI16 = unsafe { NonZeroI16::new_unchecked(int_i16) };
-    let _: NonZeroI32 = unsafe { NonZeroI32::new_unchecked(int_i32) };
-    let _: NonZeroI64 = unsafe { NonZeroI64::new_unchecked(int_i64) };
-    let _: NonZeroI128 = unsafe { NonZeroI128::new_unchecked(int_i128) };
+    let _: NonZero<i8> = unsafe { NonZero::new_unchecked(int_i8) };
+    let _: NonZero<i16> = unsafe { NonZero::new_unchecked(int_i16) };
+    let _: NonZero<i32> = unsafe { NonZero::new_unchecked(int_i32) };
+    let _: NonZero<i64> = unsafe { NonZero::new_unchecked(int_i64) };
+    let _: NonZero<i128> = unsafe { NonZero::new_unchecked(int_i128) };
 }
diff --git a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr
index bb0b0d0..199b8ec 100644
--- a/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr
+++ b/src/tools/clippy/tests/ui/transmute_int_to_non_zero.stderr
@@ -1,65 +1,65 @@
-error: transmute from a `u8` to a `NonZeroU8`
-  --> tests/ui/transmute_int_to_non_zero.rs:19:33
+error: transmute from a `u8` to a `NonZero<u8>`
+  --> tests/ui/transmute_int_to_non_zero.rs:19:35
    |
-LL |     let _: NonZeroU8 = unsafe { std::mem::transmute(int_u8) };
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU8::new_unchecked(int_u8)`
+LL |     let _: NonZero<u8> = unsafe { std::mem::transmute(int_u8) };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_u8)`
    |
    = note: `-D clippy::transmute-int-to-non-zero` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::transmute_int_to_non_zero)]`
 
-error: transmute from a `u16` to a `NonZeroU16`
-  --> tests/ui/transmute_int_to_non_zero.rs:22:34
+error: transmute from a `u16` to a `NonZero<u16>`
+  --> tests/ui/transmute_int_to_non_zero.rs:22:36
    |
-LL |     let _: NonZeroU16 = unsafe { std::mem::transmute(int_u16) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU16::new_unchecked(int_u16)`
+LL |     let _: NonZero<u16> = unsafe { std::mem::transmute(int_u16) };
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_u16)`
 
-error: transmute from a `u32` to a `NonZeroU32`
-  --> tests/ui/transmute_int_to_non_zero.rs:24:34
+error: transmute from a `u32` to a `NonZero<u32>`
+  --> tests/ui/transmute_int_to_non_zero.rs:24:36
    |
-LL |     let _: NonZeroU32 = unsafe { std::mem::transmute(int_u32) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU32::new_unchecked(int_u32)`
+LL |     let _: NonZero<u32> = unsafe { std::mem::transmute(int_u32) };
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_u32)`
 
-error: transmute from a `u64` to a `NonZeroU64`
-  --> tests/ui/transmute_int_to_non_zero.rs:26:34
+error: transmute from a `u64` to a `NonZero<u64>`
+  --> tests/ui/transmute_int_to_non_zero.rs:26:36
    |
-LL |     let _: NonZeroU64 = unsafe { std::mem::transmute(int_u64) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU64::new_unchecked(int_u64)`
+LL |     let _: NonZero<u64> = unsafe { std::mem::transmute(int_u64) };
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_u64)`
 
-error: transmute from a `u128` to a `NonZeroU128`
-  --> tests/ui/transmute_int_to_non_zero.rs:28:35
+error: transmute from a `u128` to a `NonZero<u128>`
+  --> tests/ui/transmute_int_to_non_zero.rs:28:37
    |
-LL |     let _: NonZeroU128 = unsafe { std::mem::transmute(int_u128) };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroU128::new_unchecked(int_u128)`
+LL |     let _: NonZero<u128> = unsafe { std::mem::transmute(int_u128) };
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_u128)`
 
-error: transmute from a `i8` to a `NonZeroI8`
-  --> tests/ui/transmute_int_to_non_zero.rs:31:33
+error: transmute from a `i8` to a `NonZero<i8>`
+  --> tests/ui/transmute_int_to_non_zero.rs:31:35
    |
-LL |     let _: NonZeroI8 = unsafe { std::mem::transmute(int_i8) };
-   |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI8::new_unchecked(int_i8)`
+LL |     let _: NonZero<i8> = unsafe { std::mem::transmute(int_i8) };
+   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_i8)`
 
-error: transmute from a `i16` to a `NonZeroI16`
-  --> tests/ui/transmute_int_to_non_zero.rs:33:34
+error: transmute from a `i16` to a `NonZero<i16>`
+  --> tests/ui/transmute_int_to_non_zero.rs:33:36
    |
-LL |     let _: NonZeroI16 = unsafe { std::mem::transmute(int_i16) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI16::new_unchecked(int_i16)`
+LL |     let _: NonZero<i16> = unsafe { std::mem::transmute(int_i16) };
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_i16)`
 
-error: transmute from a `i32` to a `NonZeroI32`
-  --> tests/ui/transmute_int_to_non_zero.rs:35:34
+error: transmute from a `i32` to a `NonZero<i32>`
+  --> tests/ui/transmute_int_to_non_zero.rs:35:36
    |
-LL |     let _: NonZeroI32 = unsafe { std::mem::transmute(int_i32) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI32::new_unchecked(int_i32)`
+LL |     let _: NonZero<i32> = unsafe { std::mem::transmute(int_i32) };
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_i32)`
 
-error: transmute from a `i64` to a `NonZeroI64`
-  --> tests/ui/transmute_int_to_non_zero.rs:37:34
+error: transmute from a `i64` to a `NonZero<i64>`
+  --> tests/ui/transmute_int_to_non_zero.rs:37:36
    |
-LL |     let _: NonZeroI64 = unsafe { std::mem::transmute(int_i64) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI64::new_unchecked(int_i64)`
+LL |     let _: NonZero<i64> = unsafe { std::mem::transmute(int_i64) };
+   |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_i64)`
 
-error: transmute from a `i128` to a `NonZeroI128`
-  --> tests/ui/transmute_int_to_non_zero.rs:39:35
+error: transmute from a `i128` to a `NonZero<i128>`
+  --> tests/ui/transmute_int_to_non_zero.rs:39:37
    |
-LL |     let _: NonZeroI128 = unsafe { std::mem::transmute(int_i128) };
-   |                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZeroI128::new_unchecked(int_i128)`
+LL |     let _: NonZero<i128> = unsafe { std::mem::transmute(int_i128) };
+   |                                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `NonZero::new_unchecked(int_i128)`
 
 error: aborting due to 10 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed
index ad0e5fa..2c582c9 100644
--- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed
@@ -21,6 +21,8 @@
     let _ = check_files_ref_mut(&[(FileType::Account, path)]);
     let _ = check_files_self_and_arg(&[(FileType::Account, path)]);
     let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]);
+
+    check_mut_iteratee_and_modify_inner_variable();
 }
 
 // `check_files` and its variants are based on:
@@ -138,3 +140,33 @@
 fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> {
     Ok(std::path::PathBuf::new())
 }
+
+// Issue 12098
+// https://github.com/rust-lang/rust-clippy/issues/12098
+// no message emits
+fn check_mut_iteratee_and_modify_inner_variable() {
+    struct Test {
+        list: Vec<String>,
+        mut_this: bool,
+    }
+
+    impl Test {
+        fn list(&self) -> &[String] {
+            &self.list
+        }
+    }
+
+    let mut test = Test {
+        list: vec![String::from("foo"), String::from("bar")],
+        mut_this: false,
+    };
+
+    for _item in test.list().to_vec() {
+        println!("{}", _item);
+
+        test.mut_this = true;
+        {
+            test.mut_this = true;
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs
index d3d59c4..a28ccd1 100644
--- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs
@@ -21,6 +21,8 @@
     let _ = check_files_ref_mut(&[(FileType::Account, path)]);
     let _ = check_files_self_and_arg(&[(FileType::Account, path)]);
     let _ = check_files_mut_path_buf(&[(FileType::Account, std::path::PathBuf::new())]);
+
+    check_mut_iteratee_and_modify_inner_variable();
 }
 
 // `check_files` and its variants are based on:
@@ -138,3 +140,33 @@
 fn get_file_path(_file_type: &FileType) -> Result<std::path::PathBuf, std::io::Error> {
     Ok(std::path::PathBuf::new())
 }
+
+// Issue 12098
+// https://github.com/rust-lang/rust-clippy/issues/12098
+// no message emits
+fn check_mut_iteratee_and_modify_inner_variable() {
+    struct Test {
+        list: Vec<String>,
+        mut_this: bool,
+    }
+
+    impl Test {
+        fn list(&self) -> &[String] {
+            &self.list
+        }
+    }
+
+    let mut test = Test {
+        list: vec![String::from("foo"), String::from("bar")],
+        mut_this: false,
+    };
+
+    for _item in test.list().to_vec() {
+        println!("{}", _item);
+
+        test.mut_this = true;
+        {
+            test.mut_this = true;
+        }
+    }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr
index 9d3591e..fb98cfd 100644
--- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.stderr
@@ -1,5 +1,5 @@
 error: unnecessary use of `copied`
-  --> tests/ui/unnecessary_iter_cloned.rs:29:22
+  --> tests/ui/unnecessary_iter_cloned.rs:31:22
    |
 LL |     for (t, path) in files.iter().copied() {
    |                      ^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@
    |
 
 error: unnecessary use of `copied`
-  --> tests/ui/unnecessary_iter_cloned.rs:44:22
+  --> tests/ui/unnecessary_iter_cloned.rs:46:22
    |
 LL |     for (t, path) in files.iter().copied() {
    |                      ^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed
index 8175908..231fc0a 100644
--- a/src/tools/clippy/tests/ui/useless_attribute.fixed
+++ b/src/tools/clippy/tests/ui/useless_attribute.fixed
@@ -86,8 +86,51 @@
 
 #[rustfmt::skip]
 #[allow(unused_import_braces)]
+#[allow(unused_braces)]
 use module::{Struct};
 
 fn main() {
     test_indented_attr();
 }
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/4467
+#[allow(dead_code)]
+use std::collections as puppy_doggy;
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/11595
+pub mod hidden_glob_reexports {
+    #![allow(unreachable_pub)]
+
+    mod my_prelude {
+        pub struct MyCoolTypeInternal;
+        pub use MyCoolTypeInternal as MyCoolType;
+    }
+
+    mod my_uncool_type {
+        pub(crate) struct MyUncoolType;
+    }
+
+    // This exports `MyCoolType`.
+    pub use my_prelude::*;
+
+    // This hides `my_prelude::MyCoolType`.
+    #[allow(hidden_glob_reexports)]
+    use my_uncool_type::MyUncoolType as MyCoolType;
+}
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/10878
+pub mod ambiguous_glob_exports {
+    #![allow(unreachable_pub)]
+
+    mod my_prelude {
+        pub struct MyType;
+    }
+
+    mod my_type {
+        pub struct MyType;
+    }
+
+    #[allow(ambiguous_glob_reexports)]
+    pub use my_prelude::*;
+    pub use my_type::*;
+}
diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs
index 59a9dcf..8dfcd21 100644
--- a/src/tools/clippy/tests/ui/useless_attribute.rs
+++ b/src/tools/clippy/tests/ui/useless_attribute.rs
@@ -86,8 +86,51 @@
 
 #[rustfmt::skip]
 #[allow(unused_import_braces)]
+#[allow(unused_braces)]
 use module::{Struct};
 
 fn main() {
     test_indented_attr();
 }
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/4467
+#[allow(dead_code)]
+use std::collections as puppy_doggy;
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/11595
+pub mod hidden_glob_reexports {
+    #![allow(unreachable_pub)]
+
+    mod my_prelude {
+        pub struct MyCoolTypeInternal;
+        pub use MyCoolTypeInternal as MyCoolType;
+    }
+
+    mod my_uncool_type {
+        pub(crate) struct MyUncoolType;
+    }
+
+    // This exports `MyCoolType`.
+    pub use my_prelude::*;
+
+    // This hides `my_prelude::MyCoolType`.
+    #[allow(hidden_glob_reexports)]
+    use my_uncool_type::MyUncoolType as MyCoolType;
+}
+
+// Regression test for https://github.com/rust-lang/rust-clippy/issues/10878
+pub mod ambiguous_glob_exports {
+    #![allow(unreachable_pub)]
+
+    mod my_prelude {
+        pub struct MyType;
+    }
+
+    mod my_type {
+        pub struct MyType;
+    }
+
+    #[allow(ambiguous_glob_reexports)]
+    pub use my_prelude::*;
+    pub use my_type::*;
+}
diff --git a/src/tools/clippy/tests/ui/while_float.rs b/src/tools/clippy/tests/ui/while_float.rs
new file mode 100644
index 0000000..a3b0618
--- /dev/null
+++ b/src/tools/clippy/tests/ui/while_float.rs
@@ -0,0 +1,14 @@
+#[deny(clippy::while_float)]
+fn main() {
+    let mut x = 0.0_f32;
+    while x < 42.0_f32 {
+        x += 0.5;
+    }
+    while x < 42.0 {
+        x += 1.0;
+    }
+    let mut x = 0;
+    while x < 42 {
+        x += 1;
+    }
+}
diff --git a/src/tools/clippy/tests/ui/while_float.stderr b/src/tools/clippy/tests/ui/while_float.stderr
new file mode 100644
index 0000000..b8e934b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/while_float.stderr
@@ -0,0 +1,20 @@
+error: while condition comparing floats
+  --> tests/ui/while_float.rs:4:11
+   |
+LL |     while x < 42.0_f32 {
+   |           ^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> tests/ui/while_float.rs:1:8
+   |
+LL | #[deny(clippy::while_float)]
+   |        ^^^^^^^^^^^^^^^^^^^
+
+error: while condition comparing floats
+  --> tests/ui/while_float.rs:7:11
+   |
+LL |     while x < 42.0 {
+   |           ^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/util/gh-pages/script.js b/src/tools/clippy/util/gh-pages/script.js
index c63edd5..7fd779f 100644
--- a/src/tools/clippy/util/gh-pages/script.js
+++ b/src/tools/clippy/util/gh-pages/script.js
@@ -406,7 +406,7 @@
                 }
 
                 // Search by id
-                if (lint.id.indexOf(searchStr.replace("-", "_")) !== -1) {
+                if (lint.id.indexOf(searchStr.replaceAll("-", "_")) !== -1) {
                     return true;
                 }
 
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index afbcc3e..7ff45ed 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -250,7 +250,7 @@
     /// Only run tests that match these filters
     pub filters: Vec<String>,
 
-    /// Skip tests tests matching these substrings. Corresponds to
+    /// Skip tests matching these substrings. Corresponds to
     /// `test::TestOpts::skip`. `filter_exact` does not apply to these flags.
     pub skip: Vec<String>,
 
@@ -381,7 +381,7 @@
     /// Whether to rerun tests even if the inputs are unchanged.
     pub force_rerun: bool,
 
-    /// Only rerun the tests that result has been modified accoring to Git status
+    /// Only rerun the tests that result has been modified according to Git status
     pub only_modified: bool,
 
     pub target_cfgs: OnceLock<TargetCfgs>,
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 42159b1..c7c807d 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -932,6 +932,8 @@
     "test-mir-pass",
     "unset-exec-env",
     "unset-rustc-env",
+    // Used by the tidy check `unknown_revision`.
+    "unused-revision-names",
     // tidy-alphabetical-end
 ];
 
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 2e45cae..99bde10 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -950,7 +950,7 @@
     )
 }
 
-/// Returns `true` if the given target is a MSVC target for the purpouses of CDB testing.
+/// Returns `true` if the given target is a MSVC target for the purposes of CDB testing.
 fn is_pc_windows_msvc_target(target: &str) -> bool {
     target.ends_with("-pc-windows-msvc")
 }
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 1d69ed5..02c9d38 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -2478,6 +2478,15 @@
             }
         }
 
+        let set_mir_dump_dir = |rustc: &mut Command| {
+            let mir_dump_dir = self.get_mir_dump_dir();
+            remove_and_create_dir_all(&mir_dump_dir);
+            let mut dir_opt = "-Zdump-mir-dir=".to_string();
+            dir_opt.push_str(mir_dump_dir.to_str().unwrap());
+            debug!("dir_opt: {:?}", dir_opt);
+            rustc.arg(dir_opt);
+        };
+
         match self.config.mode {
             Incremental => {
                 // If we are extracting and matching errors in the new
@@ -2532,13 +2541,7 @@
                     ]);
                 }
 
-                let mir_dump_dir = self.get_mir_dump_dir();
-                remove_and_create_dir_all(&mir_dump_dir);
-                let mut dir_opt = "-Zdump-mir-dir=".to_string();
-                dir_opt.push_str(mir_dump_dir.to_str().unwrap());
-                debug!("dir_opt: {:?}", dir_opt);
-
-                rustc.arg(dir_opt);
+                set_mir_dump_dir(&mut rustc);
             }
             CoverageMap => {
                 rustc.arg("-Cinstrument-coverage");
@@ -2560,8 +2563,11 @@
             Assembly | Codegen => {
                 rustc.arg("-Cdebug-assertions=no");
             }
+            Crashes => {
+                set_mir_dump_dir(&mut rustc);
+            }
             RunPassValgrind | Pretty | DebugInfo | Rustdoc | RustdocJson | RunMake
-            | CodegenUnits | JsDocTest | Crashes => {
+            | CodegenUnits | JsDocTest => {
                 // do not use JSON output
             }
         }
diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs
index 9e08f7e..904c2b6 100644
--- a/src/tools/jsondoclint/src/validator.rs
+++ b/src/tools/jsondoclint/src/validator.rs
@@ -21,7 +21,7 @@
 ///              it is well formed. This involves calling `check_*` functions on
 ///              fields of that item, and `add_*` functions on [`Id`]s.
 /// - `add_*`: These add an [`Id`] to the worklist, after validating it to check if
-///            the `Id` is a kind expected in this suituation.
+///            the `Id` is a kind expected in this situation.
 #[derive(Debug)]
 pub struct Validator<'a> {
     pub(crate) errs: Vec<Error>,
diff --git a/src/tools/lld-wrapper/src/main.rs b/src/tools/lld-wrapper/src/main.rs
index da94e68..79e279a 100644
--- a/src/tools/lld-wrapper/src/main.rs
+++ b/src/tools/lld-wrapper/src/main.rs
@@ -1,6 +1,6 @@
 //! Script to invoke the bundled rust-lld with the correct flavor.
 //!
-//! lld supports multiple command line interfaces. If `-flavor <flavor>` are passed as the first
+//! `lld` supports multiple command line interfaces. If `-flavor <flavor>` are passed as the first
 //! two arguments the `<flavor>` command line interface is used to process the remaining arguments.
 //! If no `-flavor` argument is present the flavor is determined by the executable name.
 //!
diff --git a/src/tools/miri/.gitignore b/src/tools/miri/.gitignore
index 924a93e..03c5591 100644
--- a/src/tools/miri/.gitignore
+++ b/src/tools/miri/.gitignore
@@ -5,9 +5,10 @@
 *.out
 *.rs.bk
 .vscode
+.helix
 *.mm_profdata
 perf.data
 perf.data.old
 flamegraph.svg
-tests/extern-so/libtestlib.so
+tests/native-lib/libtestlib.so
 .auto-*
diff --git a/src/tools/miri/CONTRIBUTING.md b/src/tools/miri/CONTRIBUTING.md
index 60bc1d5..092ad46 100644
--- a/src/tools/miri/CONTRIBUTING.md
+++ b/src/tools/miri/CONTRIBUTING.md
@@ -72,14 +72,14 @@
 
 You can (cross-)run the entire test suite using:
 
-```
+```sh
 ./miri test
-MIRI_TEST_TARGET=i686-unknown-linux-gnu ./miri test
+./miri test --target i686-unknown-linux-gnu
 ```
 
 `./miri test FILTER` only runs those tests that contain `FILTER` in their filename (including the
-base directory, e.g. `./miri test fail` will run all compile-fail tests). These filters are passed
-to `cargo test`, so for multiple filters you need to use `./miri test -- FILTER1 FILTER2`.
+base directory, e.g. `./miri test fail` will run all compile-fail tests). Multiple filters are
+supported: `./miri test FILTER1 FILTER2` runs all tests that contain either string.
 
 #### Fine grained logging
 
@@ -139,9 +139,8 @@
 in the `miri` toolchain's sysroot to prevent conflicts with other toolchains.
 The Miri binaries in the `cargo` bin directory (usually `~/.cargo/bin`) are managed by rustup.
 
-There's a test for the cargo wrapper in the `test-cargo-miri` directory; run
-`./run-test.py` in there to execute it. Like `./miri test`, this respects the
-`MIRI_TEST_TARGET` environment variable to execute the test for another target.
+There's a test for the cargo wrapper in the `test-cargo-miri` directory; run `./run-test.py` in
+there to execute it. You can pass `--target` to execute the test for another target.
 
 ### Using a modified standard library
 
@@ -287,3 +286,41 @@
 [url "git@github.com:"]
     pushInsteadOf = https://github.com/
 ```
+
+## Internal environment variables
+
+The following environment variables are *internal* and must not be used by
+anyone but Miri itself. They are used to communicate between different Miri
+binaries, and as such worth documenting:
+
+* `CARGO_EXTRA_FLAGS` is understood by `./miri` and passed to all host cargo invocations.
+* `MIRI_BE_RUSTC` can be set to `host` or `target`. It tells the Miri driver to
+  actually not interpret the code but compile it like rustc would. With `target`, Miri sets
+  some compiler flags to prepare the code for interpretation; with `host`, this is not done.
+  This environment variable is useful to be sure that the compiled `rlib`s are compatible
+  with Miri.
+* `MIRI_CALLED_FROM_SETUP` is set during the Miri sysroot build,
+  which will re-invoke `cargo-miri` as the `rustc` to use for this build.
+* `MIRI_CALLED_FROM_RUSTDOC` when set to any value tells `cargo-miri` that it is
+  running as a child process of `rustdoc`, which invokes it twice for each doc-test
+  and requires special treatment, most notably a check-only build before interpretation.
+  This is set by `cargo-miri` itself when running as a `rustdoc`-wrapper.
+* `MIRI_CWD` when set to any value tells the Miri driver to change to the given
+  directory after loading all the source files, but before commencing
+  interpretation. This is useful if the interpreted program wants a different
+  working directory at run-time than at build-time.
+* `MIRI_LOCAL_CRATES` is set by `cargo-miri` to tell the Miri driver which
+  crates should be given special treatment in diagnostics, in addition to the
+  crate currently being compiled.
+* `MIRI_ORIG_RUSTDOC` is set and read by different phases of `cargo-miri` to remember the
+  value of `RUSTDOC` from before it was overwritten.
+* `MIRI_REPLACE_LIBRS_IF_NOT_TEST` when set to any value enables a hack that helps bootstrap
+  run the standard library tests in Miri.
+* `MIRI_TEST_TARGET` is set by `./miri test` (and `./x.py test miri`) to tell the test harness about
+  the chosen target.
+* `MIRI_VERBOSE` when set to any value tells the various `cargo-miri` phases to
+  perform verbose logging.
+* `MIRI_HOST_SYSROOT` is set by bootstrap to tell `cargo-miri` which sysroot to use for *host*
+  operations.
+* `RUSTC_BLESS` is set by `./miri test` (and `./x.py test miri`) to indicate bless-mode to the test
+  harness.
diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md
index 5b3e2a5..208a8b9 100644
--- a/src/tools/miri/README.md
+++ b/src/tools/miri/README.md
@@ -1,39 +1,34 @@
 # Miri
 
-An experimental interpreter for [Rust][rust]'s
-[mid-level intermediate representation][mir] (MIR). It can run binaries and
-test suites of cargo projects and detect certain classes of
-[undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html),
-for example:
+Miri is an [Undefined Behavior][reference-ub] detection tool for Rust. It can run binaries and test
+suites of cargo projects and detect unsafe code that fails to uphold its safety requirements. For
+instance:
 
 * Out-of-bounds memory accesses and use-after-free
 * Invalid use of uninitialized data
 * Violation of intrinsic preconditions (an [`unreachable_unchecked`] being
   reached, calling [`copy_nonoverlapping`] with overlapping ranges, ...)
 * Not sufficiently aligned memory accesses and references
-* Violation of *some* basic type invariants (a `bool` that is not 0 or 1, for example,
+* Violation of basic type invariants (a `bool` that is not 0 or 1, for example,
   or an invalid enum discriminant)
 * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing
   for reference types
 * **Experimental**: Violations of the [Tree Borrows] aliasing rules, as an optional
   alternative to [Stacked Borrows]
-* **Experimental**: Data races
+* **Experimental**: Data races and emulation of weak memory effects, i.e.,
+  atomic reads can return outdated values.
 
 On top of that, Miri will also tell you about memory leaks: when there is memory
 still allocated at the end of the execution, and that memory is not reachable
 from a global `static`, Miri will raise an error.
 
-Miri supports almost all Rust language features; in particular, unwinding and
-concurrency are properly supported (including some experimental emulation of
-weak memory effects, i.e., reads can return outdated values).
-
 You can use Miri to emulate programs on other targets, e.g. to ensure that
 byte-level data manipulation works correctly both on little-endian and
 big-endian systems. See
 [cross-interpretation](#cross-interpretation-running-for-different-targets)
 below.
 
-Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you
+Miri has already discovered many [real-world bugs](#bugs-found-by-miri). If you
 found a bug with Miri, we'd appreciate if you tell us and we'll add it to the
 list!
 
@@ -45,24 +40,27 @@
 (In particular, the "fake" system RNG APIs make Miri **not suited for
 cryptographic use**! Do not generate keys using Miri.)
 
-All that said, be aware that Miri will **not catch all cases of undefined
-behavior** in your program, and cannot run all programs:
+All that said, be aware that Miri does **not catch every violation of the Rust specification** in
+your program, not least because there is no such specification. Miri uses its own approximation of
+what is and is not Undefined Behavior in Rust. To the best of our knowledge, all Undefined Behavior
+that has the potential to affect a program's correctness *is* being detected by Miri (modulo
+[bugs][I-misses-ub]), but you should consult [the Reference][reference-ub] for the official
+definition of Undefined Behavior. Miri will be updated with the Rust compiler to protect against UB
+as it is understood by the current compiler, but it makes no promises about future versions of
+rustc.
 
-* There are still plenty of open questions around the basic invariants for some
-  types and when these invariants even have to hold. Miri tries to avoid false
-  positives here, so if your program runs fine in Miri right now that is by no
-  means a guarantee that it is UB-free when these questions get answered.
+Further caveats that Miri users should be aware of:
 
-    In particular, Miri does not check that references point to valid data.
 * If the program relies on unspecified details of how data is laid out, it will
   still run fine in Miri -- but might break (including causing UB) on different
-  compiler versions or different platforms.
+  compiler versions or different platforms. (You can use `-Zrandomize-layout`
+  to detect some of these cases.)
 * Program execution is non-deterministic when it depends, for example, on where
   exactly in memory allocations end up, or on the exact interleaving of
   concurrent threads. Miri tests one of many possible executions of your
-  program. You can alleviate this to some extent by running Miri with different
-  values for `-Zmiri-seed`, but that will still by far not explore all possible
-  executions.
+  program, but it will miss bugs that only occur in a different possible execution.
+  You can alleviate this to some extent by running Miri with different
+  values for `-Zmiri-seed`, but that will still by far not explore all possible executions.
 * Miri runs the program as a platform-independent interpreter, so the program
   has no access to most platform-specific APIs or FFI. A few APIs have been
   implemented (such as printing to stdout, accessing environment variables, and
@@ -70,8 +68,8 @@
   not support networking. System API support varies between targets; if you run
   on Windows it is a good idea to use `--target x86_64-unknown-linux-gnu` to get
   better support.
-* Weak memory emulation may [produce weak behaviours](https://github.com/rust-lang/miri/issues/2301)
-  unobservable by compiled programs running on real hardware when `SeqCst` fences are used, and it
+* Weak memory emulation may [produce weak behaviors](https://github.com/rust-lang/miri/issues/2301)
+  when `SeqCst` fences are used that are not actually permitted by the Rust memory model, and it
   cannot produce all behaviors possibly observable on real hardware.
 
 Moreover, Miri fundamentally cannot tell you whether your code is *sound*. [Soundness] is the property
@@ -87,6 +85,8 @@
 [Stacked Borrows]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md
 [Tree Borrows]: https://perso.crans.org/vanille/treebor/
 [Soundness]: https://rust-lang.github.io/unsafe-code-guidelines/glossary.html#soundness-of-code--of-a-library
+[reference-ub]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+[I-misses-ub]: https://github.com/rust-lang/miri/labels/I-misses-UB
 
 
 ## Using Miri
@@ -97,14 +97,8 @@
 rustup +nightly component add miri
 ```
 
-If `rustup` says the `miri` component is unavailable, that's because not all
-nightly releases come with all tools. Check out
-[this website](https://rust-lang.github.io/rustup-components-history) to
-determine a nightly version that comes with Miri and install that using `rustup
-toolchain install nightly-YYYY-MM-DD`. Either way, all of the following commands
-assume the right toolchain is pinned via `rustup override set nightly` or
-`rustup override set nightly-YYYY-MM-DD`. (Alternatively, use `cargo
-+nightly`/`cargo +nightly-YYYY-MM-DD` for each of the following commands.)
+All the following commands assume the nightly toolchain is pinned via `rustup override set nightly`.
+Alternatively, use `cargo +nightly` for each of the following commands.
 
 Now you can run your project in Miri:
 
@@ -118,12 +112,12 @@
 example, `cargo miri test filter` only runs the tests containing `filter` in
 their name.
 
-You can pass arguments to Miri via `MIRIFLAGS`. For example,
+You can pass [flags][miri-flags] to Miri via `MIRIFLAGS`. For example,
 `MIRIFLAGS="-Zmiri-disable-stacked-borrows" cargo miri run` runs the program
 without checking the aliasing of references.
 
 When compiling code via `cargo miri`, the `cfg(miri)` config flag is set for code
-that will be interpret under Miri. You can use this to ignore test cases that fail
+that will be interpreted under Miri. You can use this to ignore test cases that fail
 under Miri because they do things Miri does not support:
 
 ```rust
@@ -159,10 +153,8 @@
 
 ### Running Miri on CI
 
-To run Miri on CI, make sure that you handle the case where the latest nightly
-does not ship the Miri component because it currently does not build. `rustup
-toolchain install --component` knows how to handle this situation, so the
-following snippet should always work:
+When running Miri on CI, use the following snippet to install a nightly toolchain with the Miri
+component:
 
 ```sh
 rustup toolchain install nightly --component miri
@@ -227,7 +219,7 @@
 - We have unofficial support (not maintained by the Miri team itself) for some further operating systems.
   - `freebsd`: **maintainer wanted**. Supports `std::env` and parts of `std::{thread, fs}`, but not `std::sync`.
   - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works.
-  - `illumos`: maintained by @devnexen. Support very incomplete, but a basic "hello world" works.
+  - `solaris` / `illumos`: maintained by @devnexen. Support very incomplete, but a basic "hello world" works.
   - `wasm`: **maintainer wanted**. Support very incomplete, not even standard output works, but an empty `main` function works.
 - For targets on other operating systems, Miri might fail before even reaching the `main` function.
 
@@ -273,25 +265,12 @@
 RUST_BACKTRACE=1 MIRIFLAGS="-Zmiri-disable-isolation" cargo miri test
 ```
 
-#### "found possibly newer version of crate `std` which `<dependency>` depends on"
-
-Your build directory may contain artifacts from an earlier build that have/have
-not been built for Miri. Run `cargo clean` before switching from non-Miri to
-Miri builds and vice-versa.
-
 #### "found crate `std` compiled by an incompatible version of rustc"
 
 You may be running `cargo miri` with a different compiler version than the one
 used to build the custom libstd that Miri uses, and Miri failed to detect that.
 Try running `cargo miri clean`.
 
-#### "no mir for `std::rt::lang_start_internal`"
-
-This means the sysroot you are using was not compiled with Miri in mind.  This
-should never happen when you use `cargo miri` because that takes care of setting
-up the sysroot.  If you are using `miri` (the Miri driver) directly, see the
-[contributors' guide](CONTRIBUTING.md) for how to use `./miri` to best do that.
-
 
 ## Miri `-Z` flags and environment variables
 [miri-flags]: #miri--z-flags-and-environment-variables
@@ -395,17 +374,17 @@
   this flag is **unsound**.
 * `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak
   memory effects.
-* `-Zmiri-extern-so-file=<path to a shared object file>` is an experimental flag for providing support
-  for FFI calls. Functions not provided by that file are still executed via the usual Miri shims.
-  **WARNING**: If an invalid/incorrect `.so` file is specified, this can cause undefined behaviour in Miri itself!
-  And of course, Miri cannot do any checks on the actions taken by the external code.
+* `-Zmiri-native-lib=<path to a shared object file>` is an experimental flag for providing support
+  for calling native functions from inside the interpreter via FFI. Functions not provided by that
+  file are still executed via the usual Miri shims.
+  **WARNING**: If an invalid/incorrect `.so` file is specified, this can cause Undefined Behavior in Miri itself!
+  And of course, Miri cannot do any checks on the actions taken by the native code.
   Note that Miri has its own handling of file descriptors, so if you want to replace *some* functions
   working on file descriptors, you will have to replace *all* of them, or the two kinds of
   file descriptors will be mixed up.
   This is **work in progress**; currently, only integer arguments and return values are
   supported (and no, pointer/integer casts to work around this limitation will not work;
-  they will fail horribly). It also only works on unix hosts for now.
-  Follow [the discussion on supporting other types](https://github.com/rust-lang/miri/issues/2365).
+  they will fail horribly). It also only works on Linux hosts for now.
 * `-Zmiri-measureme=<name>` enables `measureme` profiling for the interpreted program.
    This can be used to find which parts of your program are executing slowly under Miri.
    The profile is written out to a file inside a directory called `<name>`, and can be processed
@@ -484,50 +463,14 @@
 * `MIRI_SYSROOT` indicates the sysroot to use. When using `cargo miri`, this skips the automatic
   setup -- only set this if you do not want to use the automatically created sysroot. When invoking
   `cargo miri setup`, this indicates where the sysroot will be put.
-* `MIRI_TEST_TARGET` (recognized by `./miri {test,run}`) indicates which target
-  architecture to test against.  `miri` and `cargo miri` accept the `--target` flag for the same
-  purpose.
 * `MIRI_TEST_THREADS` (recognized by `./miri test`): set the number of threads to use for running tests.
   By default, the number of cores is used.
 * `MIRI_NO_STD` makes sure that the target's sysroot is built without libstd. This allows testing
   and running no_std programs. (Miri has a heuristic to detect no-std targets based on the target
   name; this environment variable is only needed when that heuristic fails.)
-* `RUSTC_BLESS` (recognized by `./miri test` and `cargo-miri-test/run-test.py`): overwrite all
-  `stderr` and `stdout` files instead of checking whether the output matches.
 * `MIRI_SKIP_UI_CHECKS` (recognized by `./miri test`): don't check whether the
   `stderr` or `stdout` files match the actual output.
 
-The following environment variables are *internal* and must not be used by
-anyone but Miri itself. They are used to communicate between different Miri
-binaries, and as such worth documenting:
-
-* `MIRI_BE_RUSTC` can be set to `host` or `target`. It tells the Miri driver to
-  actually not interpret the code but compile it like rustc would. With `target`, Miri sets
-  some compiler flags to prepare the code for interpretation; with `host`, this is not done.
-  This environment variable is useful to be sure that the compiled `rlib`s are compatible
-  with Miri.
-* `MIRI_CALLED_FROM_SETUP` is set during the Miri sysroot build,
-  which will re-invoke `cargo-miri` as the `rustc` to use for this build.
-* `MIRI_CALLED_FROM_RUSTDOC` when set to any value tells `cargo-miri` that it is
-  running as a child process of `rustdoc`, which invokes it twice for each doc-test
-  and requires special treatment, most notably a check-only build before interpretation.
-  This is set by `cargo-miri` itself when running as a `rustdoc`-wrapper.
-* `MIRI_CWD` when set to any value tells the Miri driver to change to the given
-  directory after loading all the source files, but before commencing
-  interpretation. This is useful if the interpreted program wants a different
-  working directory at run-time than at build-time.
-* `MIRI_LOCAL_CRATES` is set by `cargo-miri` to tell the Miri driver which
-  crates should be given special treatment in diagnostics, in addition to the
-  crate currently being compiled.
-* `MIRI_ORIG_RUSTDOC` is set and read by different phases of `cargo-miri` to remember the
-  value of `RUSTDOC` from before it was overwritten.
-* `MIRI_REPLACE_LIBRS_IF_NOT_TEST` when set to any value enables a hack that helps bootstrap
-  run the standard library tests in Miri.
-* `MIRI_VERBOSE` when set to any value tells the various `cargo-miri` phases to
-  perform verbose logging.
-* `MIRI_HOST_SYSROOT` is set by bootstrap to tell `cargo-miri` which sysroot to use for *host*
-  operations.
-
 [testing-miri]: CONTRIBUTING.md#testing-the-miri-driver
 
 ## Miri `extern` functions
diff --git a/src/tools/miri/cargo-miri/Cargo.lock b/src/tools/miri/cargo-miri/Cargo.lock
index b8ead46..8bd8f10 100644
--- a/src/tools/miri/cargo-miri/Cargo.lock
+++ b/src/tools/miri/cargo-miri/Cargo.lock
@@ -178,9 +178,9 @@
 
 [[package]]
 name = "rustc-build-sysroot"
-version = "0.4.7"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab1dbbd1bdf65fdac44c885f6cca147ba179108ce284b60a08ccc04b1f1dbac0"
+checksum = "fa3ca63cc537c1cb69e4c2c0afc5fda2ccd36ac84c97d5a4ae05e69b1c834afb"
 dependencies = [
  "anyhow",
  "rustc_version",
diff --git a/src/tools/miri/cargo-miri/Cargo.toml b/src/tools/miri/cargo-miri/Cargo.toml
index b16068b..6acdbc4 100644
--- a/src/tools/miri/cargo-miri/Cargo.toml
+++ b/src/tools/miri/cargo-miri/Cargo.toml
@@ -18,7 +18,7 @@
 rustc_version = "0.4"
 serde_json = "1.0.40"
 cargo_metadata = "0.18.0"
-rustc-build-sysroot = "0.4.6"
+rustc-build-sysroot = "0.5.2"
 
 # Enable some feature flags that dev-dependencies need but dependencies
 # do not.  This makes `./miri install` after `./miri build` faster.
diff --git a/src/tools/miri/cargo-miri/src/setup.rs b/src/tools/miri/cargo-miri/src/setup.rs
index 9a58e6f..fe67aad 100644
--- a/src/tools/miri/cargo-miri/src/setup.rs
+++ b/src/tools/miri/cargo-miri/src/setup.rs
@@ -2,11 +2,10 @@
 
 use std::env;
 use std::ffi::OsStr;
-use std::fmt::Write;
 use std::path::PathBuf;
 use std::process::{self, Command};
 
-use rustc_build_sysroot::{BuildMode, SysrootBuilder, SysrootConfig};
+use rustc_build_sysroot::{BuildMode, SysrootBuilder, SysrootConfig, SysrootStatus};
 use rustc_version::VersionMeta;
 
 use crate::util::*;
@@ -24,6 +23,7 @@
     let only_setup = matches!(subcommand, MiriCommand::Setup);
     let ask_user = !only_setup;
     let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path
+    let show_setup = only_setup && !print_sysroot;
     if !only_setup {
         if let Some(sysroot) = std::env::var_os("MIRI_SYSROOT") {
             // Skip setup step if MIRI_SYSROOT is explicitly set, *unless* we are `cargo miri setup`.
@@ -115,18 +115,16 @@
         // `config.toml`.
         command.env("RUSTC_WRAPPER", "");
 
-        if only_setup && !print_sysroot {
+        if show_setup {
             // Forward output. Even make it verbose, if requested.
+            command.stdout(process::Stdio::inherit());
+            command.stderr(process::Stdio::inherit());
             for _ in 0..verbose {
                 command.arg("-v");
             }
             if quiet {
                 command.arg("--quiet");
             }
-        } else {
-            // Suppress output.
-            command.stdout(process::Stdio::null());
-            command.stderr(process::Stdio::null());
         }
 
         command
@@ -137,49 +135,52 @@
     // not apply `RUSTFLAGS` to the sysroot either.
     let rustflags = &["-Cdebug-assertions=off", "-Coverflow-checks=on"];
 
+    let mut after_build_output = String::new(); // what should be printed when the build is done.
+    let notify = || {
+        if !quiet {
+            eprint!("Preparing a sysroot for Miri (target: {target})");
+            if verbose > 0 {
+                eprint!(" in {}", sysroot_dir.display());
+            }
+            if show_setup {
+                // Cargo will print things, so we need to finish this line.
+                eprintln!("...");
+                after_build_output = format!(
+                    "A sysroot for Miri is now available in `{}`.\n",
+                    sysroot_dir.display()
+                );
+            } else {
+                // Keep all output on a single line.
+                eprint!("... ");
+                after_build_output = format!("done\n");
+            }
+        }
+    };
+
     // Do the build.
-    if print_sysroot || quiet {
-        // Be silent.
-    } else {
-        let mut msg = String::new();
-        write!(msg, "Preparing a sysroot for Miri (target: {target})").unwrap();
-        if verbose > 0 {
-            write!(msg, " in {}", sysroot_dir.display()).unwrap();
-        }
-        write!(msg, "...").unwrap();
-        if only_setup {
-            // We want to be explicit.
-            eprintln!("{msg}");
-        } else {
-            // We want to be quiet, but still let the user know that something is happening.
-            eprint!("{msg} ");
-        }
-    }
-    SysrootBuilder::new(&sysroot_dir, target)
+    let status = SysrootBuilder::new(&sysroot_dir, target)
         .build_mode(BuildMode::Check)
         .rustc_version(rustc_version.clone())
         .sysroot_config(sysroot_config)
         .rustflags(rustflags)
         .cargo(cargo_cmd)
-        .build_from_source(&rust_src)
-        .unwrap_or_else(|err| {
-            if print_sysroot {
-                show_error!("failed to build sysroot")
-            } else if only_setup {
-                show_error!("failed to build sysroot: {err:?}")
-            } else {
-                show_error!(
-                    "failed to build sysroot; run `cargo miri setup` to see the error details"
-                )
-            }
-        });
-    if print_sysroot || quiet {
-        // Be silent.
-    } else if only_setup {
-        eprintln!("A sysroot for Miri is now available in `{}`.", sysroot_dir.display());
-    } else {
-        eprintln!("done");
+        .when_build_required(notify)
+        .build_from_source(&rust_src);
+    match status {
+        Ok(SysrootStatus::AlreadyCached) =>
+            if !quiet && show_setup {
+                eprintln!(
+                    "A sysroot for Miri is already available in `{}`.",
+                    sysroot_dir.display()
+                );
+            },
+        Ok(SysrootStatus::SysrootBuilt) => {
+            // Print what `notify` prepared.
+            eprint!("{after_build_output}");
+        }
+        Err(err) => show_error!("failed to build sysroot: {err:?}"),
     }
+
     if print_sysroot {
         // Print just the sysroot and nothing else to stdout; this way we do not need any escaping.
         println!("{}", sysroot_dir.display());
diff --git a/src/tools/miri/cargo-miri/src/util.rs b/src/tools/miri/cargo-miri/src/util.rs
index d99957d..28a824e 100644
--- a/src/tools/miri/cargo-miri/src/util.rs
+++ b/src/tools/miri/cargo-miri/src/util.rs
@@ -269,7 +269,7 @@
     output
 }
 
-/// Determines where the sysroot of this exeuction is
+/// Determines where the sysroot of this execution is
 ///
 /// Either in a user-specified spot by an envar, or in a default cache location.
 pub fn get_sysroot_dir() -> PathBuf {
diff --git a/src/tools/miri/ci/ci.sh b/src/tools/miri/ci/ci.sh
index 713c978..4e92169 100755
--- a/src/tools/miri/ci/ci.sh
+++ b/src/tools/miri/ci/ci.sh
@@ -31,24 +31,26 @@
 endgroup
 
 # Run tests. Recognizes these variables:
-# - MIRI_TEST_TARGET: the target to test. Empty for host target.
+# - TEST_TARGET: the target to test. Empty for host target.
 # - GC_STRESS: if non-empty, run the GC stress test for the main test suite.
 # - MIR_OPT: if non-empty, re-run test `pass` tests with mir-opt-level=4
 # - MANY_SEEDS: if set to N, run the "many-seeds" tests N times
 # - TEST_BENCH: if non-empty, check that the benchmarks all build
 # - CARGO_MIRI_ENV: if non-empty, set some env vars and config to potentially confuse cargo-miri
 function run_tests {
-  if [ -n "${MIRI_TEST_TARGET-}" ]; then
-    begingroup "Testing foreign architecture $MIRI_TEST_TARGET"
+  if [ -n "${TEST_TARGET-}" ]; then
+    begingroup "Testing foreign architecture $TEST_TARGET"
+    TARGET_FLAG="--target $TEST_TARGET"
   else
     begingroup "Testing host architecture"
+    TARGET_FLAG=""
   fi
 
   ## ui test suite
   if [ -n "${GC_STRESS-}" ]; then
-    time MIRIFLAGS="${MIRIFLAGS-} -Zmiri-provenance-gc=1" ./miri test
+    time MIRIFLAGS="${MIRIFLAGS-} -Zmiri-provenance-gc=1" ./miri test $TARGET_FLAG
   else
-    time ./miri test
+    time ./miri test $TARGET_FLAG
   fi
 
   ## advanced tests
@@ -59,17 +61,17 @@
     # them. Also error locations change so we don't run the failing tests.
     # We explicitly enable debug-assertions here, they are disabled by -O but we have tests
     # which exist to check that we panic on debug assertion failures.
-    time MIRIFLAGS="${MIRIFLAGS-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic}
+    time MIRIFLAGS="${MIRIFLAGS-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test $TARGET_FLAG tests/{pass,panic}
   fi
   if [ -n "${MANY_SEEDS-}" ]; then
     # Also run some many-seeds tests.
     time for FILE in tests/many-seeds/*.rs; do
-      ./miri run "--many-seeds=0..$MANY_SEEDS" "$FILE"
+      ./miri run "--many-seeds=0..$MANY_SEEDS" $TARGET_FLAG "$FILE"
     done
   fi
   if [ -n "${TEST_BENCH-}" ]; then
     # Check that the benchmarks build and run, but only once.
-    time HYPERFINE="hyperfine -w0 -r1" ./miri bench
+    time HYPERFINE="hyperfine -w0 -r1" ./miri bench $TARGET_FLAG
   fi
 
   ## test-cargo-miri
@@ -91,7 +93,7 @@
     echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml
   fi
   # Run the actual test
-  time ${PYTHON} test-cargo-miri/run-test.py
+  time ${PYTHON} test-cargo-miri/run-test.py $TARGET_FLAG
   # Clean up
   unset RUSTC MIRI
   rm -rf .cargo
@@ -100,17 +102,18 @@
 }
 
 function run_tests_minimal {
-  if [ -n "${MIRI_TEST_TARGET-}" ]; then
-    begingroup "Testing MINIMAL foreign architecture $MIRI_TEST_TARGET: only testing $@"
+  if [ -n "${TEST_TARGET-}" ]; then
+    begingroup "Testing MINIMAL foreign architecture $TEST_TARGET: only testing $@"
+    TARGET_FLAG="--target $TEST_TARGET"
   else
-    echo "run_tests_minimal requires MIRI_TEST_TARGET to be set"
+    echo "run_tests_minimal requires TEST_TARGET to be set"
     exit 1
   fi
 
-  time ./miri test -- "$@"
+  time ./miri test $TARGET_FLAG "$@"
 
   # Ensure that a small smoke test of cargo-miri works.
-  time cargo miri run --manifest-path test-cargo-miri/no-std-smoke/Cargo.toml --target ${MIRI_TEST_TARGET-$HOST_TARGET}
+  time cargo miri run --manifest-path test-cargo-miri/no-std-smoke/Cargo.toml $TARGET_FLAG
 
   endgroup
 }
@@ -126,34 +129,33 @@
     # Extra tier 1
     # With reduced many-seed count to avoid spending too much time on that.
     # (All OSes and ABIs are run with 64 seeds at least once though via the macOS runner.)
-    MANY_SEEDS=16 MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests
-    MANY_SEEDS=16 MIRI_TEST_TARGET=aarch64-unknown-linux-gnu run_tests
-    MANY_SEEDS=16 MIRI_TEST_TARGET=x86_64-apple-darwin run_tests
-    MANY_SEEDS=16 MIRI_TEST_TARGET=x86_64-pc-windows-gnu run_tests
+    MANY_SEEDS=16 TEST_TARGET=i686-unknown-linux-gnu run_tests
+    MANY_SEEDS=16 TEST_TARGET=aarch64-unknown-linux-gnu run_tests
+    MANY_SEEDS=16 TEST_TARGET=x86_64-apple-darwin run_tests
+    MANY_SEEDS=16 TEST_TARGET=x86_64-pc-windows-gnu run_tests
     ;;
   aarch64-apple-darwin)
     # Host (tier 2)
     GC_STRESS=1 MIR_OPT=1 MANY_SEEDS=64 TEST_BENCH=1 CARGO_MIRI_ENV=1 run_tests
     # Extra tier 1
-    MANY_SEEDS=64 MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests
-    MANY_SEEDS=64 MIRI_TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests
+    MANY_SEEDS=64 TEST_TARGET=i686-pc-windows-gnu run_tests
+    MANY_SEEDS=64 TEST_TARGET=x86_64-pc-windows-msvc CARGO_MIRI_ENV=1 run_tests
     # Extra tier 2
-    MIRI_TEST_TARGET=arm-unknown-linux-gnueabi run_tests
-    MIRI_TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice
+    TEST_TARGET=arm-unknown-linux-gnueabi run_tests
+    TEST_TARGET=s390x-unknown-linux-gnu run_tests # big-endian architecture of choice
     # Partially supported targets (tier 2)
-    VERY_BASIC="integer vec string btreemap" # common things we test on all of them (if they have std), requires no target-specific shims
-    BASIC="$VERY_BASIC hello hashmap alloc align" # ensures we have the shims for stdout and basic data structures
-    MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC panic/panic concurrency/simple atomic threadname libc-misc libc-random libc-time fs env num_cpus
-    MIRI_TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC panic/panic concurrency/simple atomic threadname libc-misc libc-random libc-time fs env num_cpus
-    MIRI_TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $VERY_BASIC hello panic/panic concurrency/simple pthread-sync libc-misc libc-random
-    # TODO fix solaris stack guard
-    # MIRI_TEST_TARGET=x86_64-pc-solaris run_tests_minimal $VERY_BASIC hello panic/panic pthread-sync
-    MIRI_TEST_TARGET=aarch64-linux-android  run_tests_minimal $VERY_BASIC hello panic/panic
-    MIRI_TEST_TARGET=wasm32-wasi run_tests_minimal $VERY_BASIC wasm
-    MIRI_TEST_TARGET=wasm32-unknown-unknown run_tests_minimal $VERY_BASIC wasm
-    MIRI_TEST_TARGET=thumbv7em-none-eabihf run_tests_minimal no_std
+    BASIC="empty_main integer vec string btreemap hello hashmap heap_alloc align" # ensures we have the basics: stdout/stderr, system allocator, randomness (for HashMap initialization)
+    UNIX="panic/panic panic/unwind concurrency/simple atomic libc-mem libc-misc libc-random env num_cpus" # the things that are very similar across all Unixes, and hence easily supported there
+    TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal $BASIC $UNIX threadname libc-time fs
+    TEST_TARGET=i686-unknown-freebsd   run_tests_minimal $BASIC $UNIX threadname libc-time fs
+    TEST_TARGET=x86_64-unknown-illumos run_tests_minimal $BASIC $UNIX pthread-sync
+    TEST_TARGET=x86_64-pc-solaris      run_tests_minimal $BASIC $UNIX pthread-sync
+    TEST_TARGET=aarch64-linux-android  run_tests_minimal $BASIC $UNIX
+    TEST_TARGET=wasm32-wasip2          run_tests_minimal empty_main wasm heap_alloc libc-mem
+    TEST_TARGET=wasm32-unknown-unknown run_tests_minimal empty_main wasm
+    TEST_TARGET=thumbv7em-none-eabihf  run_tests_minimal no_std
     # Custom target JSON file
-    MIRI_TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std
+    TEST_TARGET=tests/avr.json MIRI_NO_STD=1 run_tests_minimal no_std
     ;;
   i686-pc-windows-msvc)
     # Host
@@ -163,7 +165,7 @@
     # Extra tier 1
     # We really want to ensure a Linux target works on a Windows host,
     # and a 64bit target works on a 32bit host.
-    MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests
+    TEST_TARGET=x86_64-unknown-linux-gnu run_tests
     ;;
   *)
     echo "FATAL: unknown host target: $HOST_TARGET"
diff --git a/src/tools/miri/miri-script/src/args.rs b/src/tools/miri/miri-script/src/args.rs
new file mode 100644
index 0000000..16a2175
--- /dev/null
+++ b/src/tools/miri/miri-script/src/args.rs
@@ -0,0 +1,136 @@
+use std::env;
+use std::iter;
+
+use anyhow::{bail, Result};
+
+pub struct Args {
+    args: iter::Peekable<env::Args>,
+    /// Set to `true` once we saw a `--`.
+    terminated: bool,
+}
+
+impl Args {
+    pub fn new() -> Self {
+        let mut args = Args { args: env::args().peekable(), terminated: false };
+        args.args.next().unwrap(); // skip program name
+        args
+    }
+
+    /// Get the next argument without any interpretation.
+    pub fn next_raw(&mut self) -> Option<String> {
+        self.args.next()
+    }
+
+    /// Consume a `-$f` flag if present.
+    pub fn get_short_flag(&mut self, flag: char) -> Result<bool> {
+        if self.terminated {
+            return Ok(false);
+        }
+        if let Some(next) = self.args.peek() {
+            if let Some(next) = next.strip_prefix("-") {
+                if let Some(next) = next.strip_prefix(flag) {
+                    if next.is_empty() {
+                        self.args.next().unwrap(); // consume this argument
+                        return Ok(true);
+                    } else {
+                        bail!("`-{flag}` followed by value");
+                    }
+                }
+            }
+        }
+        Ok(false)
+    }
+
+    /// Consume a `--$name` flag if present.
+    pub fn get_long_flag(&mut self, name: &str) -> Result<bool> {
+        if self.terminated {
+            return Ok(false);
+        }
+        if let Some(next) = self.args.peek() {
+            if let Some(next) = next.strip_prefix("--") {
+                if next == name {
+                    self.args.next().unwrap(); // consume this argument
+                    return Ok(true);
+                }
+            }
+        }
+        Ok(false)
+    }
+
+    /// Consume a `--$name val` or `--$name=val` option if present.
+    pub fn get_long_opt(&mut self, name: &str) -> Result<Option<String>> {
+        assert!(!name.is_empty());
+        if self.terminated {
+            return Ok(None);
+        }
+        let Some(next) = self.args.peek() else { return Ok(None) };
+        let Some(next) = next.strip_prefix("--") else { return Ok(None) };
+        let Some(next) = next.strip_prefix(name) else { return Ok(None) };
+        // Starts with `--flag`.
+        Ok(if let Some(val) = next.strip_prefix("=") {
+            // `--flag=val` form
+            let val = val.into();
+            self.args.next().unwrap(); // consume this argument
+            Some(val)
+        } else if next.is_empty() {
+            // `--flag val` form
+            self.args.next().unwrap(); // consume this argument
+            let Some(val) = self.args.next() else { bail!("`--{name}` not followed by value") };
+            Some(val)
+        } else {
+            // Some unrelated flag, like `--flag-more` or so.
+            None
+        })
+    }
+
+    /// Consume a `--$name=val` or `--$name` option if present; the latter
+    /// produces a default value. (`--$name val` is *not* accepted for this form
+    /// of argument, it understands `val` already as the next argument!)
+    pub fn get_long_opt_with_default(
+        &mut self,
+        name: &str,
+        default: &str,
+    ) -> Result<Option<String>> {
+        assert!(!name.is_empty());
+        if self.terminated {
+            return Ok(None);
+        }
+        let Some(next) = self.args.peek() else { return Ok(None) };
+        let Some(next) = next.strip_prefix("--") else { return Ok(None) };
+        let Some(next) = next.strip_prefix(name) else { return Ok(None) };
+        // Starts with `--flag`.
+        Ok(if let Some(val) = next.strip_prefix("=") {
+            // `--flag=val` form
+            let val = val.into();
+            self.args.next().unwrap(); // consume this argument
+            Some(val)
+        } else if next.is_empty() {
+            // `--flag` form
+            self.args.next().unwrap(); // consume this argument
+            Some(default.into())
+        } else {
+            // Some unrelated flag, like `--flag-more` or so.
+            None
+        })
+    }
+
+    /// Returns the next free argument or uninterpreted flag, or `None` if there are no more
+    /// arguments left. `--` is returned as well, but it is interpreted in the sense that no more
+    /// flags will be parsed after this.
+    pub fn get_other(&mut self) -> Option<String> {
+        if self.terminated {
+            return self.args.next();
+        }
+        let next = self.args.next()?;
+        if next == "--" {
+            self.terminated = true; // don't parse any more flags
+            // This is where our parser is special, we do yield the `--`.
+        }
+        Some(next)
+    }
+
+    /// Return the rest of the aguments entirely unparsed.
+    pub fn remainder(self) -> Vec<String> {
+        self.args.collect()
+    }
+}
diff --git a/src/tools/miri/miri-script/src/commands.rs b/src/tools/miri/miri-script/src/commands.rs
index 6d07455..be0fdbc 100644
--- a/src/tools/miri/miri-script/src/commands.rs
+++ b/src/tools/miri/miri-script/src/commands.rs
@@ -1,5 +1,5 @@
 use std::env;
-use std::ffi::OsString;
+use std::ffi::{OsStr, OsString};
 use std::io::Write;
 use std::ops::Not;
 use std::ops::Range;
@@ -23,7 +23,13 @@
 
 impl MiriEnv {
     /// Returns the location of the sysroot.
-    fn build_miri_sysroot(&mut self, quiet: bool) -> Result<PathBuf> {
+    ///
+    /// If the target is None the sysroot will be built for the host machine.
+    fn build_miri_sysroot(
+        &mut self,
+        quiet: bool,
+        target: Option<impl AsRef<OsStr>>,
+    ) -> Result<PathBuf> {
         if let Some(miri_sysroot) = self.sh.var_os("MIRI_SYSROOT") {
             // Sysroot already set, use that.
             return Ok(miri_sysroot.into());
@@ -35,31 +41,27 @@
         self.build(path!(self.miri_dir / "Cargo.toml"), &[], quiet)?;
         self.build(&manifest_path, &[], quiet)?;
 
-        let target = &match self.sh.var("MIRI_TEST_TARGET") {
-            Ok(target) => vec!["--target".into(), target],
-            Err(_) => vec![],
+        let target_flag = if let Some(target) = &target {
+            vec![OsStr::new("--target"), target.as_ref()]
+        } else {
+            vec![]
         };
+        let target_flag = &target_flag;
+
         if !quiet {
-            match self.sh.var("MIRI_TEST_TARGET") {
-                Ok(target) => eprintln!("$ (building Miri sysroot for {target})"),
-                Err(_) => eprintln!("$ (building Miri sysroot)"),
+            eprint!("$ cargo miri setup");
+            if let Some(target) = &target {
+                eprint!(" --target {target}", target = target.as_ref().to_string_lossy());
             }
+            eprintln!();
         }
-        let output = cmd!(self.sh,
+
+        let mut cmd = cmd!(self.sh,
             "cargo +{toolchain} --quiet run {cargo_extra_flags...} --manifest-path {manifest_path} --
-             miri setup --print-sysroot {target...}"
-        ).read();
-        let Ok(output) = output else {
-            // Run it again (without `--print-sysroot` or `--quiet`) so the user can see the error.
-            cmd!(
-                self.sh,
-                "cargo +{toolchain} run {cargo_extra_flags...} --manifest-path {manifest_path} --
-                miri setup {target...}"
-            )
-            .run()
-            .with_context(|| "`cargo miri setup` failed")?;
-            panic!("`cargo miri setup` didn't fail again the 2nd time?");
-        };
+             miri setup --print-sysroot {target_flag...}"
+        );
+        cmd.set_quiet(quiet);
+        let output = cmd.read()?;
         self.sh.set_var("MIRI_SYSROOT", &output);
         Ok(output.into())
     }
@@ -161,20 +163,20 @@
             Command::Install { flags } => Self::install(flags),
             Command::Build { flags } => Self::build(flags),
             Command::Check { flags } => Self::check(flags),
-            Command::Test { bless, flags } => Self::test(bless, flags),
-            Command::Run { dep, verbose, many_seeds, flags } =>
-                Self::run(dep, verbose, many_seeds, flags),
+            Command::Test { bless, flags, target } => Self::test(bless, flags, target),
+            Command::Run { dep, verbose, many_seeds, target, edition, flags } =>
+                Self::run(dep, verbose, many_seeds, target, edition, flags),
             Command::Fmt { flags } => Self::fmt(flags),
             Command::Clippy { flags } => Self::clippy(flags),
             Command::Cargo { flags } => Self::cargo(flags),
-            Command::Bench { benches } => Self::bench(benches),
+            Command::Bench { target, benches } => Self::bench(target, benches),
             Command::Toolchain { flags } => Self::toolchain(flags),
             Command::RustcPull { commit } => Self::rustc_pull(commit.clone()),
             Command::RustcPush { github_user, branch } => Self::rustc_push(github_user, branch),
         }
     }
 
-    fn toolchain(flags: Vec<OsString>) -> Result<()> {
+    fn toolchain(flags: Vec<String>) -> Result<()> {
         // Make sure rustup-toolchain-install-master is installed.
         which::which("rustup-toolchain-install-master")
             .context("Please install rustup-toolchain-install-master by running 'cargo install rustup-toolchain-install-master'")?;
@@ -251,7 +253,7 @@
         cmd!(sh, "git fetch http://localhost:{JOSH_PORT}/rust-lang/rust.git@{commit}{JOSH_FILTER}.git")
             .run()
             .map_err(|e| {
-                // Try to un-do the previous `git commit`, to leave the repo in the state we found it it.
+                // 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");
@@ -369,7 +371,7 @@
         Ok(())
     }
 
-    fn bench(benches: Vec<OsString>) -> Result<()> {
+    fn bench(target: Option<String>, benches: Vec<String>) -> Result<()> {
         // The hyperfine to use
         let hyperfine = env::var("HYPERFINE");
         let hyperfine = hyperfine.as_deref().unwrap_or("hyperfine -w 1 -m 5 --shell=none");
@@ -377,23 +379,29 @@
         let Some((program_name, args)) = hyperfine.split_first() else {
             bail!("expected HYPERFINE environment variable to be non-empty");
         };
-        // Extra flags to pass to cargo.
-        let cargo_extra_flags = std::env::var("CARGO_EXTRA_FLAGS").unwrap_or_default();
         // Make sure we have an up-to-date Miri installed and selected the right toolchain.
         Self::install(vec![])?;
 
         let sh = Shell::new()?;
         sh.change_dir(miri_dir()?);
         let benches_dir = "bench-cargo-miri";
-        let benches = if benches.is_empty() {
+        let benches: Vec<OsString> = if benches.is_empty() {
             sh.read_dir(benches_dir)?
                 .into_iter()
                 .filter(|path| path.is_dir())
                 .map(Into::into)
                 .collect()
         } else {
-            benches.to_owned()
+            benches.into_iter().map(Into::into).collect()
         };
+        let target_flag = if let Some(target) = target {
+            let mut flag = OsString::from("--target=");
+            flag.push(target);
+            flag
+        } else {
+            OsString::new()
+        };
+        let target_flag = &target_flag;
         // Run the requested benchmarks
         for bench in benches {
             let current_bench = path!(benches_dir / bench / "Cargo.toml");
@@ -401,35 +409,35 @@
             // That seems to make Windows CI happy.
             cmd!(
                 sh,
-                "{program_name} {args...} 'cargo miri run '{cargo_extra_flags}' --manifest-path \"'{current_bench}'\"'"
+                "{program_name} {args...} 'cargo miri run '{target_flag}' --manifest-path \"'{current_bench}'\"'"
             )
             .run()?;
         }
         Ok(())
     }
 
-    fn install(flags: Vec<OsString>) -> Result<()> {
+    fn install(flags: Vec<String>) -> Result<()> {
         let e = MiriEnv::new()?;
         e.install_to_sysroot(e.miri_dir.clone(), &flags)?;
         e.install_to_sysroot(path!(e.miri_dir / "cargo-miri"), &flags)?;
         Ok(())
     }
 
-    fn build(flags: Vec<OsString>) -> Result<()> {
+    fn build(flags: Vec<String>) -> Result<()> {
         let e = MiriEnv::new()?;
         e.build(path!(e.miri_dir / "Cargo.toml"), &flags, /* quiet */ false)?;
         e.build(path!(e.miri_dir / "cargo-miri" / "Cargo.toml"), &flags, /* quiet */ false)?;
         Ok(())
     }
 
-    fn check(flags: Vec<OsString>) -> Result<()> {
+    fn check(flags: Vec<String>) -> Result<()> {
         let e = MiriEnv::new()?;
         e.check(path!(e.miri_dir / "Cargo.toml"), &flags)?;
         e.check(path!(e.miri_dir / "cargo-miri" / "Cargo.toml"), &flags)?;
         Ok(())
     }
 
-    fn clippy(flags: Vec<OsString>) -> Result<()> {
+    fn clippy(flags: Vec<String>) -> Result<()> {
         let e = MiriEnv::new()?;
         e.clippy(path!(e.miri_dir / "Cargo.toml"), &flags)?;
         e.clippy(path!(e.miri_dir / "cargo-miri" / "Cargo.toml"), &flags)?;
@@ -437,7 +445,7 @@
         Ok(())
     }
 
-    fn cargo(flags: Vec<OsString>) -> Result<()> {
+    fn cargo(flags: Vec<String>) -> Result<()> {
         let e = MiriEnv::new()?;
         let toolchain = &e.toolchain;
         // We carefully kept the working dir intact, so this will run cargo *on the workspace in the
@@ -446,16 +454,26 @@
         Ok(())
     }
 
-    fn test(bless: bool, flags: Vec<OsString>) -> Result<()> {
+    fn test(bless: bool, mut flags: Vec<String>, target: Option<String>) -> Result<()> {
         let mut e = MiriEnv::new()?;
-        // Prepare a sysroot.
-        e.build_miri_sysroot(/* quiet */ false)?;
 
-        // Then test, and let caller control flags.
-        // Only in root project as `cargo-miri` has no tests.
+        // Prepare a sysroot.
+        e.build_miri_sysroot(/* quiet */ false, target.as_deref())?;
+
+        // Forward information to test harness.
         if bless {
             e.sh.set_var("RUSTC_BLESS", "Gesundheit");
         }
+        if let Some(target) = target {
+            // Tell the harness which target to test.
+            e.sh.set_var("MIRI_TEST_TARGET", target);
+        }
+
+        // Make sure the flags are going to the test harness, not cargo.
+        flags.insert(0, "--".into());
+
+        // Then test, and let caller control flags.
+        // Only in root project as `cargo-miri` has no tests.
         e.test(path!(e.miri_dir / "Cargo.toml"), &flags)?;
         Ok(())
     }
@@ -464,37 +482,30 @@
         dep: bool,
         verbose: bool,
         many_seeds: Option<Range<u32>>,
-        mut flags: Vec<OsString>,
+        target: Option<String>,
+        edition: Option<String>,
+        flags: Vec<String>,
     ) -> Result<()> {
         let mut e = MiriEnv::new()?;
-        // Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so
-        // that we set the MIRI_SYSROOT up the right way. We must make sure that
-        // MIRI_TEST_TARGET and `--target` are in sync.
-        use itertools::Itertools;
-        let target = flags
-            .iter()
-            .take_while(|arg| *arg != "--")
-            .tuple_windows()
-            .find(|(first, _)| *first == "--target");
-        if let Some((_, target)) = target {
-            // Found it!
-            e.sh.set_var("MIRI_TEST_TARGET", target);
-        } else if let Ok(target) = std::env::var("MIRI_TEST_TARGET") {
-            // Convert `MIRI_TEST_TARGET` into `--target`.
-            flags.push("--target".into());
-            flags.push(target.into());
-        }
-        // Scan for "--edition", set one ourselves if that flag is not present.
-        let have_edition =
-            flags.iter().take_while(|arg| *arg != "--").any(|arg| *arg == "--edition");
-        if !have_edition {
-            flags.push("--edition=2021".into()); // keep in sync with `tests/ui.rs`.`
-        }
+        // More flags that we will pass before `flags`
+        // (because `flags` may contain `--`).
+        let mut early_flags = Vec::<OsString>::new();
 
-        // Prepare a sysroot, and add it to the flags.
-        let miri_sysroot = e.build_miri_sysroot(/* quiet */ !verbose)?;
-        flags.push("--sysroot".into());
-        flags.push(miri_sysroot.into());
+        // Add target, edition to flags.
+        if let Some(target) = &target {
+            early_flags.push("--target".into());
+            early_flags.push(target.into());
+        }
+        if verbose {
+            early_flags.push("--verbose".into());
+        }
+        early_flags.push("--edition".into());
+        early_flags.push(edition.as_deref().unwrap_or("2021").into());
+
+        // Prepare a sysroot, add it to the flags.
+        let miri_sysroot = e.build_miri_sysroot(/* quiet */ !verbose, target.as_deref())?;
+        early_flags.push("--sysroot".into());
+        early_flags.push(miri_sysroot.into());
 
         // Compute everything needed to run the actual command. Also add MIRIFLAGS.
         let miri_manifest = path!(e.miri_dir / "Cargo.toml");
@@ -520,7 +531,7 @@
             };
             cmd.set_quiet(!verbose);
             // Add Miri flags
-            let cmd = cmd.args(&miri_flags).args(seed_flag).args(&flags);
+            let cmd = cmd.args(&miri_flags).args(&seed_flag).args(&early_flags).args(&flags);
             // And run the thing.
             Ok(cmd.run()?)
         };
@@ -539,7 +550,7 @@
         Ok(())
     }
 
-    fn fmt(flags: Vec<OsString>) -> Result<()> {
+    fn fmt(flags: Vec<String>) -> Result<()> {
         use itertools::Itertools;
 
         let e = MiriEnv::new()?;
@@ -561,6 +572,6 @@
             .filter_ok(|item| item.file_type().is_file())
             .map_ok(|item| item.into_path());
 
-        e.format_files(files, &e.toolchain[..], &config_path, &flags[..])
+        e.format_files(files, &e.toolchain[..], &config_path, &flags)
     }
 }
diff --git a/src/tools/miri/miri-script/src/main.rs b/src/tools/miri/miri-script/src/main.rs
index f0ebbc8..d436ef0 100644
--- a/src/tools/miri/miri-script/src/main.rs
+++ b/src/tools/miri/miri-script/src/main.rs
@@ -1,10 +1,10 @@
 #![allow(clippy::needless_question_mark)]
 
+mod args;
 mod commands;
 mod util;
 
-use std::ffi::OsString;
-use std::{env, ops::Range};
+use std::ops::Range;
 
 use anyhow::{anyhow, bail, Context, Result};
 
@@ -16,23 +16,26 @@
     /// sysroot, to prevent conflicts with other toolchains.
     Install {
         /// Flags that are passed through to `cargo install`.
-        flags: Vec<OsString>,
+        flags: Vec<String>,
     },
     /// Just build miri.
     Build {
         /// Flags that are passed through to `cargo build`.
-        flags: Vec<OsString>,
+        flags: Vec<String>,
     },
     /// Just check miri.
     Check {
         /// Flags that are passed through to `cargo check`.
-        flags: Vec<OsString>,
+        flags: Vec<String>,
     },
     /// Build miri, set up a sysroot and then run the test suite.
     Test {
         bless: bool,
-        /// Flags that are passed through to `cargo test`.
-        flags: Vec<OsString>,
+        /// The cross-interpretation target.
+        /// If none then the host is the target.
+        target: Option<String>,
+        /// Flags that are passed through to the test harness.
+        flags: Vec<String>,
     },
     /// Build miri, set up a sysroot and then run the driver with the given <flags>.
     /// (Also respects MIRIFLAGS environment variable.)
@@ -40,32 +43,35 @@
         dep: bool,
         verbose: bool,
         many_seeds: Option<Range<u32>>,
+        target: Option<String>,
+        edition: Option<String>,
         /// Flags that are passed through to `miri`.
-        flags: Vec<OsString>,
+        flags: Vec<String>,
     },
     /// Format all sources and tests.
     Fmt {
         /// Flags that are passed through to `rustfmt`.
-        flags: Vec<OsString>,
+        flags: Vec<String>,
     },
     /// Runs clippy on all sources.
     Clippy {
         /// Flags that are passed through to `cargo clippy`.
-        flags: Vec<OsString>,
+        flags: Vec<String>,
     },
     /// Runs just `cargo <flags>` with the Miri-specific environment variables.
     /// Mainly meant to be invoked by rust-analyzer.
-    Cargo { flags: Vec<OsString> },
+    Cargo { flags: Vec<String> },
     /// Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed.
     Bench {
+        target: Option<String>,
         /// List of benchmarks to run. By default all benchmarks are run.
-        benches: Vec<OsString>,
+        benches: Vec<String>,
     },
     /// Update and activate the rustup toolchain 'miri' to the commit given in the
     /// `rust-version` file.
     /// `rustup-toolchain-install-master` must be installed for this to work. Any extra
     /// flags are passed to `rustup-toolchain-install-master`.
-    Toolchain { flags: Vec<OsString> },
+    Toolchain { flags: Vec<String> },
     /// Pull and merge Miri changes from the rustc repo. Defaults to fetching the latest
     /// rustc commit. The fetched commit is stored in the `rust-version` file, so the
     /// next `./miri toolchain` will install the rustc that just got pulled.
@@ -84,9 +90,9 @@
 ./miri check <flags>:
 Just check miri. <flags> are passed to `cargo check`.
 
-./miri test [--bless] <flags>:
-Build miri, set up a sysroot and then run the test suite. <flags> are passed
-to the final `cargo test` invocation.
+./miri test [--bless] [--target <target>] <flags>:
+Build miri, set up a sysroot and then run the test suite.
+<flags> are passed to the test harness.
 
 ./miri run [--dep] [-v|--verbose] [--many-seeds|--many-seeds=..to|--many-seeds=from..to] <flags>:
 Build miri, set up a sysroot and then run the driver with the given <flags>.
@@ -110,7 +116,7 @@
 working directory. Note that the binaries are placed in the `miri` toolchain
 sysroot, to prevent conflicts with other toolchains.
 
-./miri bench <benches>:
+./miri bench [--target <target>] <benches>:
 Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed.
 <benches> can explicitly list the benchmarks to run; by default, all of them are run.
 
@@ -141,73 +147,95 @@
 fn main() -> Result<()> {
     // We are hand-rolling our own argument parser, since `clap` can't express what we need
     // (https://github.com/clap-rs/clap/issues/5055).
-    let mut args = env::args_os().peekable();
-    args.next().unwrap(); // skip program name
-    let command = match args.next().and_then(|s| s.into_string().ok()).as_deref() {
-        Some("build") => Command::Build { flags: args.collect() },
-        Some("check") => Command::Check { flags: args.collect() },
+    let mut args = args::Args::new();
+    let command = match args.next_raw().as_deref() {
+        Some("build") => Command::Build { flags: args.remainder() },
+        Some("check") => Command::Check { flags: args.remainder() },
         Some("test") => {
-            let bless = args.peek().is_some_and(|a| a.to_str() == Some("--bless"));
-            if bless {
-                // Consume the flag.
-                args.next().unwrap();
+            let mut target = None;
+            let mut bless = false;
+            let mut flags = Vec::new();
+            loop {
+                if args.get_long_flag("bless")? {
+                    bless = true;
+                } else if let Some(val) = args.get_long_opt("target")? {
+                    target = Some(val);
+                } else if let Some(flag) = args.get_other() {
+                    flags.push(flag);
+                } else {
+                    break;
+                }
             }
-            Command::Test { bless, flags: args.collect() }
+            Command::Test { bless, flags, target }
         }
         Some("run") => {
             let mut dep = false;
             let mut verbose = false;
             let mut many_seeds = None;
-            while let Some(arg) = args.peek().and_then(|s| s.to_str()) {
-                if arg == "--dep" {
+            let mut target = None;
+            let mut edition = None;
+            let mut flags = Vec::new();
+            loop {
+                if args.get_long_flag("dep")? {
                     dep = true;
-                } else if arg == "-v" || arg == "--verbose" {
+                } else if args.get_long_flag("verbose")? || args.get_short_flag('v')? {
                     verbose = true;
-                } else if arg == "--many-seeds" {
-                    many_seeds = Some(0..256);
-                } else if let Some(val) = arg.strip_prefix("--many-seeds=") {
+                } else if let Some(val) = args.get_long_opt_with_default("many-seeds", "0..256")? {
                     let (from, to) = val.split_once("..").ok_or_else(|| {
-                        anyhow!("invalid format for `--many-seeds`: expected `from..to`")
+                        anyhow!("invalid format for `--many-seeds-range`: expected `from..to`")
                     })?;
                     let from: u32 = if from.is_empty() {
                         0
                     } else {
-                        from.parse().context("invalid `from` in `--many-seeds=from..to")?
+                        from.parse().context("invalid `from` in `--many-seeds-range=from..to")?
                     };
-                    let to: u32 = to.parse().context("invalid `to` in `--many-seeds=from..to")?;
+                    let to: u32 =
+                        to.parse().context("invalid `to` in `--many-seeds-range=from..to")?;
                     many_seeds = Some(from..to);
+                } else if let Some(val) = args.get_long_opt("target")? {
+                    target = Some(val);
+                } else if let Some(val) = args.get_long_opt("edition")? {
+                    edition = Some(val);
+                } else if let Some(flag) = args.get_other() {
+                    flags.push(flag);
                 } else {
-                    break; // not for us
+                    break;
                 }
-                // Consume the flag, look at the next one.
-                args.next().unwrap();
             }
-            Command::Run { dep, verbose, many_seeds, flags: args.collect() }
+            Command::Run { dep, verbose, many_seeds, target, edition, flags }
         }
-        Some("fmt") => Command::Fmt { flags: args.collect() },
-        Some("clippy") => Command::Clippy { flags: args.collect() },
-        Some("cargo") => Command::Cargo { flags: args.collect() },
-        Some("install") => Command::Install { flags: args.collect() },
-        Some("bench") => Command::Bench { benches: args.collect() },
-        Some("toolchain") => Command::Toolchain { flags: args.collect() },
+        Some("fmt") => Command::Fmt { flags: args.remainder() },
+        Some("clippy") => Command::Clippy { flags: args.remainder() },
+        Some("cargo") => Command::Cargo { flags: args.remainder() },
+        Some("install") => Command::Install { flags: args.remainder() },
+        Some("bench") => {
+            let mut target = None;
+            let mut benches = Vec::new();
+            loop {
+                if let Some(val) = args.get_long_opt("target")? {
+                    target = Some(val);
+                } else if let Some(flag) = args.get_other() {
+                    benches.push(flag);
+                } else {
+                    break;
+                }
+            }
+            Command::Bench { target, benches }
+        }
+        Some("toolchain") => Command::Toolchain { flags: args.remainder() },
         Some("rustc-pull") => {
-            let commit = args.next().map(|a| a.to_string_lossy().into_owned());
-            if args.next().is_some() {
+            let commit = args.next_raw();
+            if args.next_raw().is_some() {
                 bail!("Too many arguments for `./miri rustc-pull`");
             }
             Command::RustcPull { commit }
         }
         Some("rustc-push") => {
-            let github_user = args
-                .next()
-                .ok_or_else(|| {
-                    anyhow!("Missing first argument for `./miri rustc-push GITHUB_USER [BRANCH]`")
-                })?
-                .to_string_lossy()
-                .into_owned();
-            let branch =
-                args.next().unwrap_or_else(|| "miri-sync".into()).to_string_lossy().into_owned();
-            if args.next().is_some() {
+            let github_user = args.next_raw().ok_or_else(|| {
+                anyhow!("Missing first argument for `./miri rustc-push GITHUB_USER [BRANCH]`")
+            })?;
+            let branch = args.next_raw().unwrap_or_else(|| "miri-sync".into());
+            if args.next_raw().is_some() {
                 bail!("Too many arguments for `./miri rustc-push GITHUB_USER BRANCH`");
             }
             Command::RustcPush { github_user, branch }
diff --git a/src/tools/miri/miri-script/src/util.rs b/src/tools/miri/miri-script/src/util.rs
index 23b5e93..e9095a4 100644
--- a/src/tools/miri/miri-script/src/util.rs
+++ b/src/tools/miri/miri-script/src/util.rs
@@ -109,7 +109,7 @@
     pub fn build(
         &self,
         manifest_path: impl AsRef<OsStr>,
-        args: &[OsString],
+        args: &[String],
         quiet: bool,
     ) -> Result<()> {
         let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
@@ -125,21 +125,21 @@
         Ok(())
     }
 
-    pub fn check(&self, manifest_path: impl AsRef<OsStr>, args: &[OsString]) -> Result<()> {
+    pub fn check(&self, manifest_path: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
         let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
         cmd!(self.sh, "cargo +{toolchain} check {cargo_extra_flags...} --manifest-path {manifest_path} --all-targets {args...}")
             .run()?;
         Ok(())
     }
 
-    pub fn clippy(&self, manifest_path: impl AsRef<OsStr>, args: &[OsString]) -> Result<()> {
+    pub fn clippy(&self, manifest_path: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
         let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
         cmd!(self.sh, "cargo +{toolchain} clippy {cargo_extra_flags...} --manifest-path {manifest_path} --all-targets {args...}")
             .run()?;
         Ok(())
     }
 
-    pub fn test(&self, manifest_path: impl AsRef<OsStr>, args: &[OsString]) -> Result<()> {
+    pub fn test(&self, manifest_path: impl AsRef<OsStr>, args: &[String]) -> Result<()> {
         let MiriEnv { toolchain, cargo_extra_flags, .. } = self;
         cmd!(
             self.sh,
@@ -157,7 +157,7 @@
         files: impl Iterator<Item = Result<PathBuf, walkdir::Error>>,
         toolchain: &str,
         config_path: &Path,
-        flags: &[OsString],
+        flags: &[String],
     ) -> anyhow::Result<()> {
         use itertools::Itertools;
 
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index ca6f4d5..207ef6c 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-d568423a7a4ddb4b49323d96078a22f94df55fbd
+6579ed89f0fcc26da71afdd11d30d63f6f812a0a
diff --git a/src/tools/miri/src/alloc_bytes.rs b/src/tools/miri/src/alloc_bytes.rs
new file mode 100644
index 0000000..7952abd
--- /dev/null
+++ b/src/tools/miri/src/alloc_bytes.rs
@@ -0,0 +1,109 @@
+use std::alloc;
+use std::alloc::Layout;
+use std::borrow::Cow;
+use std::slice;
+
+use rustc_middle::mir::interpret::AllocBytes;
+use rustc_target::abi::{Align, Size};
+
+/// Allocation bytes that explicitly handle the layout of the data they're storing.
+/// This is necessary to interface with native code that accesses the program store in Miri.
+#[derive(Debug)]
+pub struct MiriAllocBytes {
+    /// Stored layout information about the allocation.
+    layout: alloc::Layout,
+    /// Pointer to the allocation contents.
+    /// Invariant:
+    /// * If `self.layout.size() == 0`, then `self.ptr` is some suitably aligned pointer
+    ///   without provenance (and no actual memory was allocated).
+    /// * Otherwise, `self.ptr` points to memory allocated with `self.layout`.
+    ptr: *mut u8,
+}
+
+impl Clone for MiriAllocBytes {
+    fn clone(&self) -> Self {
+        let bytes: Cow<'_, [u8]> = Cow::Borrowed(self);
+        let align = Align::from_bytes(self.layout.align().try_into().unwrap()).unwrap();
+        MiriAllocBytes::from_bytes(bytes, align)
+    }
+}
+
+impl Drop for MiriAllocBytes {
+    fn drop(&mut self) {
+        if self.layout.size() != 0 {
+            // SAFETY: Invariant, `self.ptr` points to memory allocated with `self.layout`.
+            unsafe { alloc::dealloc(self.ptr, self.layout) }
+        }
+    }
+}
+
+impl std::ops::Deref for MiriAllocBytes {
+    type Target = [u8];
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: `ptr` is non-null, properly aligned, and valid for reading out `self.layout.size()`-many bytes.
+        // Note that due to the invariant this is true even if `self.layout.size() == 0`.
+        unsafe { slice::from_raw_parts(self.ptr, self.layout.size()) }
+    }
+}
+
+impl std::ops::DerefMut for MiriAllocBytes {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        // SAFETY: `ptr` is non-null, properly aligned, and valid for reading out `self.layout.size()`-many bytes.
+        // Note that due to the invariant this is true even if `self.layout.size() == 0`.
+        unsafe { slice::from_raw_parts_mut(self.ptr, self.layout.size()) }
+    }
+}
+
+impl MiriAllocBytes {
+    /// This method factors out how a `MiriAllocBytes` object is allocated,
+    /// specifically given an allocation function `alloc_fn`.
+    /// `alloc_fn` is only used if `size != 0`.
+    /// Returns `Err(layout)` if the allocation function returns a `ptr` that is `ptr.is_null()`.
+    fn alloc_with(
+        size: usize,
+        align: usize,
+        alloc_fn: impl FnOnce(Layout) -> *mut u8,
+    ) -> Result<MiriAllocBytes, Layout> {
+        let layout = Layout::from_size_align(size, align).unwrap();
+        let ptr = if size == 0 {
+            std::ptr::without_provenance_mut(align)
+        } else {
+            let ptr = alloc_fn(layout);
+            if ptr.is_null() {
+                return Err(layout);
+            }
+            ptr
+        };
+        // SAFETY: All `MiriAllocBytes` invariants are fulfilled.
+        Ok(Self { ptr, layout })
+    }
+}
+
+impl AllocBytes for MiriAllocBytes {
+    fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self {
+        let slice = slice.into();
+        let size = slice.len();
+        let align = align.bytes_usize();
+        // SAFETY: `alloc_fn` will only be used if `size != 0`.
+        let alloc_fn = |layout| unsafe { alloc::alloc(layout) };
+        let alloc_bytes = MiriAllocBytes::alloc_with(size, align, alloc_fn)
+            .unwrap_or_else(|layout| alloc::handle_alloc_error(layout));
+        // SAFETY: `alloc_bytes.ptr` and `slice.as_ptr()` are non-null, properly aligned
+        // and valid for the `size`-many bytes to be copied.
+        unsafe { alloc_bytes.ptr.copy_from(slice.as_ptr(), size) };
+        alloc_bytes
+    }
+
+    fn zeroed(size: Size, align: Align) -> Option<Self> {
+        let size = size.bytes_usize();
+        let align = align.bytes_usize();
+        // SAFETY: `alloc_fn` will only be used if `size != 0`.
+        let alloc_fn = |layout| unsafe { alloc::alloc_zeroed(layout) };
+        MiriAllocBytes::alloc_with(size, align, alloc_fn).ok()
+    }
+
+    fn as_mut_ptr(&mut self) -> *mut u8 {
+        self.ptr
+    }
+}
diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs
index 44201cb..d748feb 100644
--- a/src/tools/miri/src/bin/miri.rs
+++ b/src/tools/miri/src/bin/miri.rs
@@ -405,9 +405,12 @@
 
     let mut rustc_args = vec![];
     let mut after_dashdash = false;
-
     // If user has explicitly enabled/disabled isolation
     let mut isolation_enabled: Option<bool> = None;
+
+    // Note that we require values to be given with `=`, not with a space.
+    // This matches how rustc parses `-Z`.
+    // However, unlike rustc we do not accept a space after `-Z`.
     for arg in args {
         if rustc_args.is_empty() {
             // Very first arg: binary name.
@@ -575,18 +578,15 @@
                 "full" => BacktraceStyle::Full,
                 _ => show_error!("-Zmiri-backtrace may only be 0, 1, or full"),
             };
-        } else if let Some(param) = arg.strip_prefix("-Zmiri-extern-so-file=") {
+        } else if let Some(param) = arg.strip_prefix("-Zmiri-native-lib=") {
             let filename = param.to_string();
             if std::path::Path::new(&filename).exists() {
-                if let Some(other_filename) = miri_config.external_so_file {
-                    show_error!(
-                        "-Zmiri-extern-so-file is already set to {}",
-                        other_filename.display()
-                    );
+                if let Some(other_filename) = miri_config.native_lib {
+                    show_error!("-Zmiri-native-lib is already set to {}", other_filename.display());
                 }
-                miri_config.external_so_file = Some(filename.into());
+                miri_config.native_lib = Some(filename.into());
             } else {
-                show_error!("-Zmiri-extern-so-file `{}` does not exist", filename);
+                show_error!("-Zmiri-native-lib `{}` does not exist", filename);
             }
         } else if let Some(param) = arg.strip_prefix("-Zmiri-num-cpus=") {
             let num_cpus = param
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
index a6dd1d8..3da8744 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/mod.rs
@@ -136,7 +136,7 @@
         cx: &crate::MiriInterpCx<'_, 'tcx>,
     ) -> Self {
         // `ty` is not the `Box` but the field of the Box with this pointer (due to allocator handling).
-        let pointee = ty.builtin_deref(true).unwrap().ty;
+        let pointee = ty.builtin_deref(true).unwrap();
         if pointee.is_unpin(*cx.tcx, cx.param_env()) {
             // A regular box. On `FnEntry` this is `noalias`, but not `dereferenceable` (hence only
             // a weak protector).
diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
index 55ff09c..3b6c29b 100644
--- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
+++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs
@@ -9,7 +9,7 @@
 };
 use crate::ProvenanceExtra;
 
-/// Exactly what cache size we should use is a difficult tradeoff. There will always be some
+/// Exactly what cache size we should use is a difficult trade-off. There will always be some
 /// workload which has a `BorTag` working set which exceeds the size of the cache, and ends up
 /// falling back to linear searches of the borrow stack very often.
 /// The cost of making this value too large is that the loop in `Stack::insert` which ensures the
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
index b9f0b5b..8abc853 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs
@@ -390,7 +390,7 @@
     warning_text: S,
 }
 
-/// Formating of the permissions on each range.
+/// Formatting of the permissions on each range.
 ///
 /// Example:
 /// ```rust,ignore (private type)
@@ -422,7 +422,7 @@
     range_sep: S,
 }
 
-/// Formating of the tree structure.
+/// Formatting of the tree structure.
 ///
 /// Example:
 /// ```rust,ignore (private type)
@@ -487,7 +487,7 @@
     meh: S,
 }
 
-/// All parameters to determine how the tree is formated.
+/// All parameters to determine how the tree is formatted.
 struct DisplayFmt {
     wrapper: DisplayFmtWrapper,
     perm: DisplayFmtPermission,
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
index fc5eb94..b5bf16d 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs
@@ -173,7 +173,7 @@
         cx: &crate::MiriInterpCx<'_, 'tcx>,
         zero_size: bool,
     ) -> Option<Self> {
-        let pointee = ty.builtin_deref(true).unwrap().ty;
+        let pointee = ty.builtin_deref(true).unwrap();
         pointee.is_unpin(*cx.tcx, cx.param_env()).then_some(()).map(|()| {
             // Regular `Unpin` box, give it `noalias` but only a weak protector
             // because it is valid to deallocate it within the function.
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
index bec51c7..28848e2 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs
@@ -202,7 +202,7 @@
         Self { inner: Frozen }
     }
 
-    /// Default initial permission of  the root of a new tre at out-of-bounds positions.
+    /// Default initial permission of  the root of a new tree at out-of-bounds positions.
     /// Must *only* be used for the root, this is not in general an "initial" permission!
     pub fn new_disabled() -> Self {
         Self { inner: Disabled }
diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
index 6777f41..19acbdb 100644
--- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
+++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs
@@ -483,7 +483,7 @@
         /// that causes UB in the target but not in the source.
         /// This implementation simply explores the reachable space
         /// by all sequences of `TestEvent`.
-        /// This function can be instanciated with `RetX` and `RetY`
+        /// This function can be instantiated with `RetX` and `RetY`
         /// among `NoRet` or `AllowRet` to resp. forbid/allow `x`/`y` to lose their
         /// protector.
         fn distinguishable<RetX, RetY>(&self, other: &Self) -> bool
diff --git a/src/tools/miri/src/concurrency/thread.rs b/src/tools/miri/src/concurrency/thread.rs
index 6953ce8..24e2c25 100644
--- a/src/tools/miri/src/concurrency/thread.rs
+++ b/src/tools/miri/src/concurrency/thread.rs
@@ -111,7 +111,7 @@
     Condvar(CondvarId),
     /// Blocked on a reader-writer lock.
     RwLock(RwLockId),
-    /// Blocled on a Futex variable.
+    /// Blocked on a Futex variable.
     Futex { addr: u64 },
     /// Blocked on an InitOnce.
     InitOnce(InitOnceId),
diff --git a/src/tools/miri/src/concurrency/weak_memory.rs b/src/tools/miri/src/concurrency/weak_memory.rs
index 574962c4..8c71eeb 100644
--- a/src/tools/miri/src/concurrency/weak_memory.rs
+++ b/src/tools/miri/src/concurrency/weak_memory.rs
@@ -48,7 +48,7 @@
 //! One consequence of this difference is that safe/sound Rust allows for more operations on atomic locations
 //! than the C++20 atomic API was intended to allow, such as non-atomically accessing
 //! a previously atomically accessed location, or accessing previously atomically accessed locations with a differently sized operation
-//! (such as accessing the top 16 bits of an AtomicU32). These scenarios are generally undiscussed in formalisations of C++ memory model.
+//! (such as accessing the top 16 bits of an AtomicU32). These scenarios are generally undiscussed in formalizations of C++ memory model.
 //! In Rust, these operations can only be done through a `&mut AtomicFoo` reference or one derived from it, therefore these operations
 //! can only happen after all previous accesses on the same locations. This implementation is adapted to allow these operations.
 //! A mixed atomicity read that races with writes, or a write that races with reads or writes will still cause UBs to be thrown.
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index cb5ed27..189c4a2 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -459,7 +459,7 @@
 
 pub fn report_leaks<'mir, 'tcx>(
     ecx: &InterpCx<'mir, 'tcx, MiriMachine<'mir, 'tcx>>,
-    leaks: Vec<(AllocId, MemoryKind, Allocation<Provenance, AllocExtra<'tcx>>)>,
+    leaks: Vec<(AllocId, MemoryKind, Allocation<Provenance, AllocExtra<'tcx>, MiriAllocBytes>)>,
 ) {
     let mut any_pruned = false;
     for (id, kind, mut alloc) in leaks {
diff --git a/src/tools/miri/src/eval.rs b/src/tools/miri/src/eval.rs
index 97c5e9a..78c092f 100644
--- a/src/tools/miri/src/eval.rs
+++ b/src/tools/miri/src/eval.rs
@@ -142,8 +142,8 @@
     /// Whether Stacked Borrows and Tree Borrows retagging should recurse into fields of datatypes.
     pub retag_fields: RetagFields,
     /// The location of a shared object file to load when calling external functions
-    /// FIXME! consider allowing users to specify paths to multiple SO files, or to a directory
-    pub external_so_file: Option<PathBuf>,
+    /// FIXME! consider allowing users to specify paths to multiple files, or to a directory
+    pub native_lib: Option<PathBuf>,
     /// Run a garbage collector for BorTags every N basic blocks.
     pub gc_interval: u32,
     /// The number of CPUs to be reported by miri.
@@ -188,7 +188,7 @@
             preemption_rate: 0.01, // 1%
             report_progress: None,
             retag_fields: RetagFields::Yes,
-            external_so_file: None,
+            native_lib: None,
             gc_interval: 10_000,
             num_cpus: 1,
             page_size: None,
diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs
index 40c2008..4050ae3 100644
--- a/src/tools/miri/src/helpers.rs
+++ b/src/tools/miri/src/helpers.rs
@@ -751,26 +751,23 @@
 
     /// This function tries to produce the most similar OS error from the `std::io::ErrorKind`
     /// as a platform-specific errnum.
-    fn io_error_to_errnum(
-        &self,
-        err_kind: std::io::ErrorKind,
-    ) -> InterpResult<'tcx, Scalar<Provenance>> {
+    fn io_error_to_errnum(&self, err: std::io::Error) -> InterpResult<'tcx, Scalar<Provenance>> {
         let this = self.eval_context_ref();
         let target = &this.tcx.sess.target;
         if target.families.iter().any(|f| f == "unix") {
             for &(name, kind) in UNIX_IO_ERROR_TABLE {
-                if err_kind == kind {
+                if err.kind() == kind {
                     return Ok(this.eval_libc(name));
                 }
             }
-            throw_unsup_format!("io error {:?} cannot be translated into a raw os error", err_kind)
+            throw_unsup_format!("unsupported io error: {err}")
         } else if target.families.iter().any(|f| f == "windows") {
             for &(name, kind) in WINDOWS_IO_ERROR_TABLE {
-                if err_kind == kind {
+                if err.kind() == kind {
                     return Ok(this.eval_windows("c", name));
                 }
             }
-            throw_unsup_format!("io error {:?} cannot be translated into a raw os error", err_kind);
+            throw_unsup_format!("unsupported io error: {err}");
         } else {
             throw_unsup_format!(
                 "converting io::Error into errnum is unsupported for OS {}",
@@ -812,8 +809,8 @@
     }
 
     /// Sets the last OS error using a `std::io::ErrorKind`.
-    fn set_last_error_from_io_error(&mut self, err_kind: std::io::ErrorKind) -> InterpResult<'tcx> {
-        self.set_last_error(self.io_error_to_errnum(err_kind)?)
+    fn set_last_error_from_io_error(&mut self, err: std::io::Error) -> InterpResult<'tcx> {
+        self.set_last_error(self.io_error_to_errnum(err)?)
     }
 
     /// Helper function that consumes an `std::io::Result<T>` and returns an
@@ -829,7 +826,7 @@
         match result {
             Ok(ok) => Ok(ok),
             Err(e) => {
-                self.eval_context_mut().set_last_error_from_io_error(e.kind())?;
+                self.eval_context_mut().set_last_error_from_io_error(e)?;
                 Ok((-1).into())
             }
         }
@@ -982,29 +979,46 @@
         Ok((true, string_length))
     }
 
-    /// Read a sequence of u16 until the first null terminator.
-    fn read_wide_str(&self, mut ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, Vec<u16>> {
+    /// Helper function to read a sequence of unsigned integers of the given size and alignment
+    /// until the first null terminator.
+    fn read_c_str_with_char_size<T>(
+        &self,
+        mut ptr: Pointer<Option<Provenance>>,
+        size: Size,
+        align: Align,
+    ) -> InterpResult<'tcx, Vec<T>>
+    where
+        T: TryFrom<u128>,
+        <T as TryFrom<u128>>::Error: std::fmt::Debug,
+    {
+        assert_ne!(size, Size::ZERO);
+
         let this = self.eval_context_ref();
-        let size2 = Size::from_bytes(2);
-        this.check_ptr_align(ptr, Align::from_bytes(2).unwrap())?;
+
+        this.check_ptr_align(ptr, align)?;
 
         let mut wchars = Vec::new();
         loop {
             // FIXME: We are re-getting the allocation each time around the loop.
             // Would be nice if we could somehow "extend" an existing AllocRange.
-            let alloc = this.get_ptr_alloc(ptr, size2)?.unwrap(); // not a ZST, so we will get a result
-            let wchar = alloc.read_integer(alloc_range(Size::ZERO, size2))?.to_u16()?;
-            if wchar == 0 {
+            let alloc = this.get_ptr_alloc(ptr, size)?.unwrap(); // not a ZST, so we will get a result
+            let wchar_int = alloc.read_integer(alloc_range(Size::ZERO, size))?.to_bits(size)?;
+            if wchar_int == 0 {
                 break;
             } else {
-                wchars.push(wchar);
-                ptr = ptr.offset(size2, this)?;
+                wchars.push(wchar_int.try_into().unwrap());
+                ptr = ptr.offset(size, this)?;
             }
         }
 
         Ok(wchars)
     }
 
+    /// Read a sequence of u16 until the first null terminator.
+    fn read_wide_str(&self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, Vec<u16>> {
+        self.read_c_str_with_char_size(ptr, Size::from_bytes(2), Align::from_bytes(2).unwrap())
+    }
+
     /// Helper function to write a sequence of u16 with an added 0x0000-terminator, which is what
     /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying
     /// to write if `size` is not large enough to fit the contents of `os_string` plus a null
@@ -1037,6 +1051,14 @@
         Ok((true, string_length))
     }
 
+    /// Read a sequence of wchar_t until the first null terminator.
+    /// Always returns a `Vec<u32>` no matter the size of `wchar_t`.
+    fn read_wchar_t_str(&self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx, Vec<u32>> {
+        let this = self.eval_context_ref();
+        let wchar_t = this.libc_ty_layout("wchar_t");
+        self.read_c_str_with_char_size(ptr, wchar_t.size, wchar_t.align.abi)
+    }
+
     /// Check that the ABI is what we expect.
     fn check_abi<'a>(&self, abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> {
         if abi != exp_abi {
diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs
index 40f6b8a..501dbc1 100644
--- a/src/tools/miri/src/intrinsics/atomic.rs
+++ b/src/tools/miri/src/intrinsics/atomic.rs
@@ -25,98 +25,98 @@
 
         let intrinsic_structure: Vec<_> = intrinsic_name.split('_').collect();
 
-        fn read_ord<'tcx>(ord: &str) -> InterpResult<'tcx, AtomicReadOrd> {
-            Ok(match ord {
+        fn read_ord(ord: &str) -> AtomicReadOrd {
+            match ord {
                 "seqcst" => AtomicReadOrd::SeqCst,
                 "acquire" => AtomicReadOrd::Acquire,
                 "relaxed" => AtomicReadOrd::Relaxed,
-                _ => throw_unsup_format!("unsupported read ordering `{ord}`"),
-            })
+                _ => panic!("invalid read ordering `{ord}`"),
+            }
         }
 
-        fn write_ord<'tcx>(ord: &str) -> InterpResult<'tcx, AtomicWriteOrd> {
-            Ok(match ord {
+        fn write_ord(ord: &str) -> AtomicWriteOrd {
+            match ord {
                 "seqcst" => AtomicWriteOrd::SeqCst,
                 "release" => AtomicWriteOrd::Release,
                 "relaxed" => AtomicWriteOrd::Relaxed,
-                _ => throw_unsup_format!("unsupported write ordering `{ord}`"),
-            })
+                _ => panic!("invalid write ordering `{ord}`"),
+            }
         }
 
-        fn rw_ord<'tcx>(ord: &str) -> InterpResult<'tcx, AtomicRwOrd> {
-            Ok(match ord {
+        fn rw_ord(ord: &str) -> AtomicRwOrd {
+            match ord {
                 "seqcst" => AtomicRwOrd::SeqCst,
                 "acqrel" => AtomicRwOrd::AcqRel,
                 "acquire" => AtomicRwOrd::Acquire,
                 "release" => AtomicRwOrd::Release,
                 "relaxed" => AtomicRwOrd::Relaxed,
-                _ => throw_unsup_format!("unsupported read-write ordering `{ord}`"),
-            })
+                _ => panic!("invalid read-write ordering `{ord}`"),
+            }
         }
 
-        fn fence_ord<'tcx>(ord: &str) -> InterpResult<'tcx, AtomicFenceOrd> {
-            Ok(match ord {
+        fn fence_ord(ord: &str) -> AtomicFenceOrd {
+            match ord {
                 "seqcst" => AtomicFenceOrd::SeqCst,
                 "acqrel" => AtomicFenceOrd::AcqRel,
                 "acquire" => AtomicFenceOrd::Acquire,
                 "release" => AtomicFenceOrd::Release,
-                _ => throw_unsup_format!("unsupported fence ordering `{ord}`"),
-            })
+                _ => panic!("invalid fence ordering `{ord}`"),
+            }
         }
 
         match &*intrinsic_structure {
-            ["load", ord] => this.atomic_load(args, dest, read_ord(ord)?)?,
-            ["store", ord] => this.atomic_store(args, write_ord(ord)?)?,
+            ["load", ord] => this.atomic_load(args, dest, read_ord(ord))?,
+            ["store", ord] => this.atomic_store(args, write_ord(ord))?,
 
-            ["fence", ord] => this.atomic_fence_intrinsic(args, fence_ord(ord)?)?,
-            ["singlethreadfence", ord] => this.compiler_fence_intrinsic(args, fence_ord(ord)?)?,
+            ["fence", ord] => this.atomic_fence_intrinsic(args, fence_ord(ord))?,
+            ["singlethreadfence", ord] => this.compiler_fence_intrinsic(args, fence_ord(ord))?,
 
-            ["xchg", ord] => this.atomic_exchange(args, dest, rw_ord(ord)?)?,
+            ["xchg", ord] => this.atomic_exchange(args, dest, rw_ord(ord))?,
             ["cxchg", ord1, ord2] =>
-                this.atomic_compare_exchange(args, dest, rw_ord(ord1)?, read_ord(ord2)?)?,
+                this.atomic_compare_exchange(args, dest, rw_ord(ord1), read_ord(ord2))?,
             ["cxchgweak", ord1, ord2] =>
-                this.atomic_compare_exchange_weak(args, dest, rw_ord(ord1)?, read_ord(ord2)?)?,
+                this.atomic_compare_exchange_weak(args, dest, rw_ord(ord1), read_ord(ord2))?,
 
             ["or", ord] =>
-                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), rw_ord(ord)?)?,
+                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), rw_ord(ord))?,
             ["xor", ord] =>
-                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), rw_ord(ord)?)?,
+                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), rw_ord(ord))?,
             ["and", ord] =>
-                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), rw_ord(ord)?)?,
+                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), rw_ord(ord))?,
             ["nand", ord] =>
-                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), rw_ord(ord)?)?,
+                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), rw_ord(ord))?,
             ["xadd", ord] =>
-                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), rw_ord(ord)?)?,
+                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), rw_ord(ord))?,
             ["xsub", ord] =>
-                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), rw_ord(ord)?)?,
+                this.atomic_rmw_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), rw_ord(ord))?,
             ["min", ord] => {
                 // Later we will use the type to indicate signed vs unsigned,
                 // so make sure it matches the intrinsic name.
                 assert!(matches!(args[1].layout.ty.kind(), ty::Int(_)));
-                this.atomic_rmw_op(args, dest, AtomicOp::Min, rw_ord(ord)?)?;
+                this.atomic_rmw_op(args, dest, AtomicOp::Min, rw_ord(ord))?;
             }
             ["umin", ord] => {
                 // Later we will use the type to indicate signed vs unsigned,
                 // so make sure it matches the intrinsic name.
                 assert!(matches!(args[1].layout.ty.kind(), ty::Uint(_)));
-                this.atomic_rmw_op(args, dest, AtomicOp::Min, rw_ord(ord)?)?;
+                this.atomic_rmw_op(args, dest, AtomicOp::Min, rw_ord(ord))?;
             }
             ["max", ord] => {
                 // Later we will use the type to indicate signed vs unsigned,
                 // so make sure it matches the intrinsic name.
                 assert!(matches!(args[1].layout.ty.kind(), ty::Int(_)));
-                this.atomic_rmw_op(args, dest, AtomicOp::Max, rw_ord(ord)?)?;
+                this.atomic_rmw_op(args, dest, AtomicOp::Max, rw_ord(ord))?;
             }
             ["umax", ord] => {
                 // Later we will use the type to indicate signed vs unsigned,
                 // so make sure it matches the intrinsic name.
                 assert!(matches!(args[1].layout.ty.kind(), ty::Uint(_)));
-                this.atomic_rmw_op(args, dest, AtomicOp::Max, rw_ord(ord)?)?;
+                this.atomic_rmw_op(args, dest, AtomicOp::Max, rw_ord(ord))?;
             }
 
             _ => return Ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
 
diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs
index d94485a..9faaeb8 100644
--- a/src/tools/miri/src/intrinsics/mod.rs
+++ b/src/tools/miri/src/intrinsics/mod.rs
@@ -26,7 +26,7 @@
         args: &[OpTy<'tcx, Provenance>],
         dest: &MPlaceTy<'tcx, Provenance>,
         ret: Option<mir::BasicBlock>,
-        _unwind: mir::UnwindAction,
+        unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, Option<ty::Instance<'tcx>>> {
         let this = self.eval_context_mut();
 
@@ -62,11 +62,16 @@
                     args: instance.args,
                 }))
             }
-            EmulateItemResult::NeedsJumping => {
+            EmulateItemResult::NeedsReturn => {
                 trace!("{:?}", this.dump_place(&dest.clone().into()));
                 this.return_to_block(ret)?;
                 Ok(None)
             }
+            EmulateItemResult::NeedsUnwind => {
+                // Jump to the unwind block to begin unwinding.
+                this.unwind_to_block(unwind)?;
+                Ok(None)
+            }
             EmulateItemResult::AlreadyJumped => Ok(None),
         }
     }
@@ -117,7 +122,7 @@
 
             "write_bytes" | "volatile_set_memory" => {
                 let [ptr, val_byte, count] = check_arg_count(args)?;
-                let ty = ptr.layout.ty.builtin_deref(true).unwrap().ty;
+                let ty = ptr.layout.ty.builtin_deref(true).unwrap();
                 let ty_layout = this.layout_of(ty)?;
                 let val_byte = this.read_scalar(val_byte)?.to_u8()?;
                 let ptr = this.read_pointer(ptr)?;
@@ -167,6 +172,7 @@
                 // This is a "bitwise" operation, so there's no NaN non-determinism.
                 this.write_scalar(Scalar::from_f64(f.abs()), dest)?;
             }
+
             "floorf32" | "ceilf32" | "truncf32" | "roundf32" | "rintf32" => {
                 let [f] = check_arg_count(args)?;
                 let f = this.read_scalar(f)?.to_f32()?;
@@ -182,6 +188,22 @@
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
             }
+            "floorf64" | "ceilf64" | "truncf64" | "roundf64" | "rintf64" => {
+                let [f] = check_arg_count(args)?;
+                let f = this.read_scalar(f)?.to_f64()?;
+                let mode = match intrinsic_name {
+                    "floorf64" => Round::TowardNegative,
+                    "ceilf64" => Round::TowardPositive,
+                    "truncf64" => Round::TowardZero,
+                    "roundf64" => Round::NearestTiesToAway,
+                    "rintf64" => Round::NearestTiesToEven,
+                    _ => bug!(),
+                };
+                let res = f.round_to_integral(mode).value;
+                let res = this.adjust_nan(res, &[f]);
+                this.write_scalar(res, dest)?;
+            }
+
             #[rustfmt::skip]
             | "sinf32"
             | "cosf32"
@@ -211,22 +233,6 @@
                 let res = this.adjust_nan(res, &[f]);
                 this.write_scalar(res, dest)?;
             }
-
-            "floorf64" | "ceilf64" | "truncf64" | "roundf64" | "rintf64" => {
-                let [f] = check_arg_count(args)?;
-                let f = this.read_scalar(f)?.to_f64()?;
-                let mode = match intrinsic_name {
-                    "floorf64" => Round::TowardNegative,
-                    "ceilf64" => Round::TowardPositive,
-                    "truncf64" => Round::TowardZero,
-                    "roundf64" => Round::NearestTiesToAway,
-                    "rintf64" => Round::NearestTiesToEven,
-                    _ => bug!(),
-                };
-                let res = f.round_to_integral(mode).value;
-                let res = this.adjust_nan(res, &[f]);
-                this.write_scalar(res, dest)?;
-            }
             #[rustfmt::skip]
             | "sinf64"
             | "cosf64"
@@ -257,6 +263,113 @@
                 this.write_scalar(res, dest)?;
             }
 
+            "minnumf32" | "maxnumf32" | "copysignf32" => {
+                let [a, b] = check_arg_count(args)?;
+                let a = this.read_scalar(a)?.to_f32()?;
+                let b = this.read_scalar(b)?.to_f32()?;
+                let res = match intrinsic_name {
+                    "minnumf32" => this.adjust_nan(a.min(b), &[a, b]),
+                    "maxnumf32" => this.adjust_nan(a.max(b), &[a, b]),
+                    "copysignf32" => a.copy_sign(b), // bitwise, no NaN adjustments
+                    _ => bug!(),
+                };
+                this.write_scalar(Scalar::from_f32(res), dest)?;
+            }
+            "minnumf64" | "maxnumf64" | "copysignf64" => {
+                let [a, b] = check_arg_count(args)?;
+                let a = this.read_scalar(a)?.to_f64()?;
+                let b = this.read_scalar(b)?.to_f64()?;
+                let res = match intrinsic_name {
+                    "minnumf64" => this.adjust_nan(a.min(b), &[a, b]),
+                    "maxnumf64" => this.adjust_nan(a.max(b), &[a, b]),
+                    "copysignf64" => a.copy_sign(b), // bitwise, no NaN adjustments
+                    _ => bug!(),
+                };
+                this.write_scalar(Scalar::from_f64(res), dest)?;
+            }
+
+            "fmaf32" => {
+                let [a, b, c] = check_arg_count(args)?;
+                let a = this.read_scalar(a)?.to_f32()?;
+                let b = this.read_scalar(b)?.to_f32()?;
+                let c = this.read_scalar(c)?.to_f32()?;
+                // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
+                let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft();
+                let res = this.adjust_nan(res, &[a, b, c]);
+                this.write_scalar(res, dest)?;
+            }
+            "fmaf64" => {
+                let [a, b, c] = check_arg_count(args)?;
+                let a = this.read_scalar(a)?.to_f64()?;
+                let b = this.read_scalar(b)?.to_f64()?;
+                let c = this.read_scalar(c)?.to_f64()?;
+                // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
+                let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft();
+                let res = this.adjust_nan(res, &[a, b, c]);
+                this.write_scalar(res, dest)?;
+            }
+
+            "powf32" => {
+                let [f1, f2] = check_arg_count(args)?;
+                let f1 = this.read_scalar(f1)?.to_f32()?;
+                let f2 = this.read_scalar(f2)?.to_f32()?;
+                // Using host floats (but it's fine, this operation does not have guaranteed precision).
+                let res = f1.to_host().powf(f2.to_host()).to_soft();
+                let res = this.adjust_nan(res, &[f1, f2]);
+                this.write_scalar(res, dest)?;
+            }
+            "powf64" => {
+                let [f1, f2] = check_arg_count(args)?;
+                let f1 = this.read_scalar(f1)?.to_f64()?;
+                let f2 = this.read_scalar(f2)?.to_f64()?;
+                // Using host floats (but it's fine, this operation does not have guaranteed precision).
+                let res = f1.to_host().powf(f2.to_host()).to_soft();
+                let res = this.adjust_nan(res, &[f1, f2]);
+                this.write_scalar(res, dest)?;
+            }
+
+            "powif32" => {
+                let [f, i] = check_arg_count(args)?;
+                let f = this.read_scalar(f)?.to_f32()?;
+                let i = this.read_scalar(i)?.to_i32()?;
+                // Using host floats (but it's fine, this operation does not have guaranteed precision).
+                let res = f.to_host().powi(i).to_soft();
+                let res = this.adjust_nan(res, &[f]);
+                this.write_scalar(res, dest)?;
+            }
+            "powif64" => {
+                let [f, i] = check_arg_count(args)?;
+                let f = this.read_scalar(f)?.to_f64()?;
+                let i = this.read_scalar(i)?.to_i32()?;
+                // Using host floats (but it's fine, this operation does not have guaranteed precision).
+                let res = f.to_host().powi(i).to_soft();
+                let res = this.adjust_nan(res, &[f]);
+                this.write_scalar(res, dest)?;
+            }
+
+            #[rustfmt::skip]
+            | "fadd_algebraic"
+            | "fsub_algebraic"
+            | "fmul_algebraic"
+            | "fdiv_algebraic"
+            | "frem_algebraic"
+            => {
+                let [a, b] = check_arg_count(args)?;
+                let a = this.read_immediate(a)?;
+                let b = this.read_immediate(b)?;
+                let op = match intrinsic_name {
+                    "fadd_algebraic" => mir::BinOp::Add,
+                    "fsub_algebraic" => mir::BinOp::Sub,
+                    "fmul_algebraic" => mir::BinOp::Mul,
+                    "fdiv_algebraic" => mir::BinOp::Div,
+                    "frem_algebraic" => mir::BinOp::Rem,
+                    _ => bug!(),
+                };
+                let res = this.wrapping_binary_op(op, &a, &b)?;
+                // `wrapping_binary_op` already called `generate_nan` if necessary.
+                this.write_immediate(*res, dest)?;
+            }
+
             #[rustfmt::skip]
             | "fadd_fast"
             | "fsub_fast"
@@ -307,102 +420,6 @@
                 this.write_immediate(*res, dest)?;
             }
 
-            #[rustfmt::skip]
-            | "minnumf32"
-            | "maxnumf32"
-            | "copysignf32"
-            => {
-                let [a, b] = check_arg_count(args)?;
-                let a = this.read_scalar(a)?.to_f32()?;
-                let b = this.read_scalar(b)?.to_f32()?;
-                let res = match intrinsic_name {
-                    "minnumf32" => this.adjust_nan(a.min(b), &[a, b]),
-                    "maxnumf32" => this.adjust_nan(a.max(b), &[a, b]),
-                    "copysignf32" => a.copy_sign(b), // bitwise, no NaN adjustments
-                    _ => bug!(),
-                };
-                this.write_scalar(Scalar::from_f32(res), dest)?;
-            }
-
-            #[rustfmt::skip]
-            | "minnumf64"
-            | "maxnumf64"
-            | "copysignf64"
-            => {
-                let [a, b] = check_arg_count(args)?;
-                let a = this.read_scalar(a)?.to_f64()?;
-                let b = this.read_scalar(b)?.to_f64()?;
-                let res = match intrinsic_name {
-                    "minnumf64" => this.adjust_nan(a.min(b), &[a, b]),
-                    "maxnumf64" => this.adjust_nan(a.max(b), &[a, b]),
-                    "copysignf64" => a.copy_sign(b), // bitwise, no NaN adjustments
-                    _ => bug!(),
-                };
-                this.write_scalar(Scalar::from_f64(res), dest)?;
-            }
-
-            "fmaf32" => {
-                let [a, b, c] = check_arg_count(args)?;
-                let a = this.read_scalar(a)?.to_f32()?;
-                let b = this.read_scalar(b)?.to_f32()?;
-                let c = this.read_scalar(c)?.to_f32()?;
-                // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
-                let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft();
-                let res = this.adjust_nan(res, &[a, b, c]);
-                this.write_scalar(res, dest)?;
-            }
-
-            "fmaf64" => {
-                let [a, b, c] = check_arg_count(args)?;
-                let a = this.read_scalar(a)?.to_f64()?;
-                let b = this.read_scalar(b)?.to_f64()?;
-                let c = this.read_scalar(c)?.to_f64()?;
-                // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
-                let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft();
-                let res = this.adjust_nan(res, &[a, b, c]);
-                this.write_scalar(res, dest)?;
-            }
-
-            "powf32" => {
-                let [f1, f2] = check_arg_count(args)?;
-                let f1 = this.read_scalar(f1)?.to_f32()?;
-                let f2 = this.read_scalar(f2)?.to_f32()?;
-                // Using host floats (but it's fine, this operation does not have guaranteed precision).
-                let res = f1.to_host().powf(f2.to_host()).to_soft();
-                let res = this.adjust_nan(res, &[f1, f2]);
-                this.write_scalar(res, dest)?;
-            }
-
-            "powf64" => {
-                let [f1, f2] = check_arg_count(args)?;
-                let f1 = this.read_scalar(f1)?.to_f64()?;
-                let f2 = this.read_scalar(f2)?.to_f64()?;
-                // Using host floats (but it's fine, this operation does not have guaranteed precision).
-                let res = f1.to_host().powf(f2.to_host()).to_soft();
-                let res = this.adjust_nan(res, &[f1, f2]);
-                this.write_scalar(res, dest)?;
-            }
-
-            "powif32" => {
-                let [f, i] = check_arg_count(args)?;
-                let f = this.read_scalar(f)?.to_f32()?;
-                let i = this.read_scalar(i)?.to_i32()?;
-                // Using host floats (but it's fine, this operation does not have guaranteed precision).
-                let res = f.to_host().powi(i).to_soft();
-                let res = this.adjust_nan(res, &[f]);
-                this.write_scalar(res, dest)?;
-            }
-
-            "powif64" => {
-                let [f, i] = check_arg_count(args)?;
-                let f = this.read_scalar(f)?.to_f64()?;
-                let i = this.read_scalar(i)?.to_i32()?;
-                // Using host floats (but it's fine, this operation does not have guaranteed precision).
-                let res = f.to_host().powi(i).to_soft();
-                let res = this.adjust_nan(res, &[f]);
-                this.write_scalar(res, dest)?;
-            }
-
             "float_to_int_unchecked" => {
                 let [val] = check_arg_count(args)?;
                 let val = this.read_immediate(val)?;
@@ -429,6 +446,6 @@
             _ => return Ok(EmulateItemResult::NotSupported),
         }
 
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/intrinsics/simd.rs b/src/tools/miri/src/intrinsics/simd.rs
index 3be98d7..e178187 100644
--- a/src/tools/miri/src/intrinsics/simd.rs
+++ b/src/tools/miri/src/intrinsics/simd.rs
@@ -42,6 +42,7 @@
             | "flog2"
             | "flog10"
             | "ctlz"
+            | "ctpop"
             | "cttz"
             | "bswap"
             | "bitreverse"
@@ -68,6 +69,7 @@
                     "round" => Op::Round(rustc_apfloat::Round::NearestTiesToAway),
                     "trunc" => Op::Round(rustc_apfloat::Round::TowardZero),
                     "ctlz" => Op::Numeric(sym::ctlz),
+                    "ctpop" => Op::Numeric(sym::ctpop),
                     "cttz" => Op::Numeric(sym::cttz),
                     "bswap" => Op::Numeric(sym::bswap),
                     "bitreverse" => Op::Numeric(sym::bitreverse),
@@ -267,7 +269,7 @@
                         Op::WrappingOffset => {
                             let ptr = left.to_scalar().to_pointer(this)?;
                             let offset_count = right.to_scalar().to_target_isize(this)?;
-                            let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty;
+                            let pointee_ty = left.layout.ty.builtin_deref(true).unwrap();
 
                             let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap();
                             let offset_bytes = offset_count.wrapping_mul(pointee_size);
@@ -746,7 +748,7 @@
 
             _ => return Ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 
     fn fminmax_op(
diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs
index 1680b98..e4879f2 100644
--- a/src/tools/miri/src/lib.rs
+++ b/src/tools/miri/src/lib.rs
@@ -12,6 +12,8 @@
 #![feature(let_chains)]
 #![feature(lint_reasons)]
 #![feature(trait_upcasting)]
+#![feature(strict_overflow_ops)]
+#![feature(strict_provenance)]
 // Configure clippy and other lints
 #![allow(
     clippy::collapsible_else_if,
@@ -73,6 +75,7 @@
 extern crate rustc_driver;
 
 mod alloc_addresses;
+mod alloc_bytes;
 mod borrow_tracker;
 mod clock;
 mod concurrency;
@@ -106,6 +109,7 @@
 pub use crate::shims::EmulateItemResult;
 
 pub use crate::alloc_addresses::{EvalContextExt as _, ProvenanceMode};
+pub use crate::alloc_bytes::MiriAllocBytes;
 pub use crate::borrow_tracker::stacked_borrows::{
     EvalContextExt as _, Item, Permission, Stack, Stacks,
 };
diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs
index 51b96bf..cbf02d7 100644
--- a/src/tools/miri/src/machine.rs
+++ b/src/tools/miri/src/machine.rs
@@ -30,14 +30,13 @@
 use rustc_target::spec::abi::Abi;
 
 use crate::{
-    concurrency::{data_race, weak_memory},
-    shims::unix,
+    concurrency::{
+        data_race::{self, NaReadType, NaWriteType},
+        weak_memory,
+    },
     *,
 };
 
-use self::concurrency::data_race::NaReadType;
-use self::concurrency::data_race::NaWriteType;
-
 /// First real-time signal.
 /// `signal(7)` says this must be between 32 and 64 and specifies 34 or 35
 /// as typical values.
@@ -206,11 +205,11 @@
     /// whether *some* exposed pointer could have done what we want to do, and if the answer is yes
     /// then we allow the access. This allows too much code in two ways:
     /// - The same wildcard pointer can "take the role" of multiple different exposed pointers on
-    ///   subsequenct memory accesses.
+    ///   subsequent memory accesses.
     /// - In the aliasing model, we don't just have to know the borrow tag of the pointer used for
     ///   the access, we also have to update the aliasing state -- and that update can be very
     ///   different depending on which borrow tag we pick! Stacked Borrows has support for this by
-    ///   switching to a stack that is only approximately known, i.e. we overapproximate the effect
+    ///   switching to a stack that is only approximately known, i.e. we over-approximate the effect
     ///   of using *any* exposed pointer for this access, and only keep information about the borrow
     ///   stack that would be true with all possible choices.
     Wildcard,
@@ -464,9 +463,9 @@
     pub(crate) validate: bool,
 
     /// The table of file descriptors.
-    pub(crate) fds: unix::FdTable,
+    pub(crate) fds: shims::FdTable,
     /// The table of directory descriptors.
-    pub(crate) dirs: unix::DirTable,
+    pub(crate) dirs: shims::DirTable,
 
     /// This machine's monotone clock.
     pub(crate) clock: Clock,
@@ -535,11 +534,11 @@
     // The total number of blocks that have been executed.
     pub(crate) basic_block_count: u64,
 
-    /// Handle of the optional shared object file for external functions.
+    /// Handle of the optional shared object file for native functions.
     #[cfg(target_os = "linux")]
-    pub external_so_lib: Option<(libloading::Library, std::path::PathBuf)>,
+    pub native_lib: Option<(libloading::Library, std::path::PathBuf)>,
     #[cfg(not(target_os = "linux"))]
-    pub external_so_lib: Option<!>,
+    pub native_lib: Option<!>,
 
     /// Run a garbage collector for BorTags every N basic blocks.
     pub(crate) gc_interval: u32,
@@ -641,7 +640,7 @@
             tls: TlsData::default(),
             isolated_op: config.isolated_op,
             validate: config.validate,
-            fds: unix::FdTable::new(config.mute_stdout_stderr),
+            fds: shims::FdTable::new(config.mute_stdout_stderr),
             dirs: Default::default(),
             layouts,
             threads: ThreadManager::default(),
@@ -665,7 +664,7 @@
             basic_block_count: 0,
             clock: Clock::new(config.isolated_op == IsolatedOp::Allow),
             #[cfg(target_os = "linux")]
-            external_so_lib: config.external_so_file.as_ref().map(|lib_file_path| {
+            native_lib: config.native_lib.as_ref().map(|lib_file_path| {
                 let target_triple = layout_cx.tcx.sess.opts.target_triple.triple();
                 // Check if host target == the session target.
                 if env!("TARGET") != target_triple {
@@ -687,7 +686,7 @@
                 )
             }),
             #[cfg(not(target_os = "linux"))]
-            external_so_lib: config.external_so_file.as_ref().map(|_| {
+            native_lib: config.native_lib.as_ref().map(|_| {
                 panic!("loading external .so files is only supported on Linux")
             }),
             gc_interval: config.gc_interval,
@@ -802,7 +801,7 @@
             preemption_rate: _,
             report_progress: _,
             basic_block_count: _,
-            external_so_lib: _,
+            native_lib: _,
             gc_interval: _,
             since_gc: _,
             num_cpus: _,
@@ -862,7 +861,7 @@
 
     type Provenance = Provenance;
     type ProvenanceExtra = ProvenanceExtra;
-    type Bytes = Box<[u8]>;
+    type Bytes = MiriAllocBytes;
 
     type MemoryMap =
         MonoHashMap<AllocId, (MemoryKind, Allocation<Provenance, Self::AllocExtra, Self::Bytes>)>;
@@ -1088,8 +1087,9 @@
         id: AllocId,
         alloc: Cow<'b, Allocation>,
         kind: Option<MemoryKind>,
-    ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra>>> {
-        let kind = kind.expect("we set our GLOBAL_KIND so this cannot be None");
+    ) -> InterpResult<'tcx, Cow<'b, Allocation<Self::Provenance, Self::AllocExtra, Self::Bytes>>>
+    {
+        let kind = kind.expect("we set our STATIC_KIND so this cannot be None");
         if ecx.machine.tracked_alloc_ids.contains(&id) {
             ecx.emit_diagnostic(NonHaltingDiagnostic::CreatedAlloc(
                 id,
@@ -1126,7 +1126,7 @@
             Some(ecx.generate_stacktrace())
         };
 
-        let alloc: Allocation<Provenance, Self::AllocExtra> = alloc.adjust_from_tcx(
+        let alloc: Allocation<Provenance, Self::AllocExtra, Self::Bytes> = alloc.adjust_from_tcx(
             &ecx.tcx,
             AllocExtra {
                 borrow_tracker,
diff --git a/src/tools/miri/src/provenance_gc.rs b/src/tools/miri/src/provenance_gc.rs
index f23d7df..ecd614b 100644
--- a/src/tools/miri/src/provenance_gc.rs
+++ b/src/tools/miri/src/provenance_gc.rs
@@ -122,7 +122,7 @@
     }
 }
 
-impl VisitProvenance for Allocation<Provenance, AllocExtra<'_>> {
+impl VisitProvenance for Allocation<Provenance, AllocExtra<'_>, MiriAllocBytes> {
     fn visit_provenance(&self, visit: &mut VisitWith<'_>) {
         for prov in self.provenance().provenances() {
             prov.visit_provenance(visit);
diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs
index 7953159..ca672bd 100644
--- a/src/tools/miri/src/shims/alloc.rs
+++ b/src/tools/miri/src/shims/alloc.rs
@@ -19,22 +19,36 @@
 
 impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
-    /// Returns the minimum alignment for the target architecture for allocations of the given size.
-    fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align {
+    /// Returns the alignment that `malloc` would guarantee for requests of the given size.
+    fn malloc_align(&self, size: u64) -> Align {
         let this = self.eval_context_ref();
-        // List taken from `library/std/src/sys/pal/common/alloc.rs`.
-        // This list should be kept in sync with the one from libstd.
-        let min_align = match this.tcx.sess.target.arch.as_ref() {
+        // The C standard says: "The pointer returned if the allocation succeeds is suitably aligned
+        // so that it may be assigned to a pointer to any type of object with a fundamental
+        // alignment requirement and size less than or equal to the size requested."
+        // So first we need to figure out what the limits are for "fundamental alignment".
+        // This is given by `alignof(max_align_t)`. The following list is taken from
+        // `library/std/src/sys/pal/common/alloc.rs` (where this is called `MIN_ALIGN`) and should
+        // be kept in sync.
+        let max_fundamental_align = match this.tcx.sess.target.arch.as_ref() {
             "x86" | "arm" | "mips" | "mips32r6" | "powerpc" | "powerpc64" | "wasm32" => 8,
             "x86_64" | "aarch64" | "mips64" | "mips64r6" | "s390x" | "sparc64" | "loongarch64" =>
                 16,
             arch => bug!("unsupported target architecture for malloc: `{}`", arch),
         };
-        // Windows always aligns, even small allocations.
-        // Source: <https://support.microsoft.com/en-us/help/286470/how-to-use-pageheap-exe-in-windows-xp-windows-2000-and-windows-server>
-        // But jemalloc does not, so for the C heap we only align if the allocation is sufficiently big.
-        if kind == MiriMemoryKind::WinHeap || size >= min_align {
-            return Align::from_bytes(min_align).unwrap();
+        // The C standard only requires sufficient alignment for any *type* with size less than or
+        // equal to the size requested. Types one can define in standard C seem to never have an alignment
+        // bigger than their size. So if the size is 2, then only alignment 2 is guaranteed, even if
+        // `max_fundamental_align` is bigger.
+        // This matches what some real-world implementations do, see e.g.
+        // - https://github.com/jemalloc/jemalloc/issues/1533
+        // - https://github.com/llvm/llvm-project/issues/53540
+        // - https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2293.htm
+        if size >= max_fundamental_align {
+            return Align::from_bytes(max_fundamental_align).unwrap();
+        }
+        // C doesn't have zero-sized types, so presumably nothing is guaranteed here.
+        if size == 0 {
+            return Align::ONE;
         }
         // We have `size < min_align`. Round `size` *down* to the next power of two and use that.
         fn prev_power_of_two(x: u64) -> u64 {
@@ -73,7 +87,7 @@
             }
             AllocatorKind::Default => {
                 default(this)?;
-                Ok(EmulateItemResult::NeedsJumping)
+                Ok(EmulateItemResult::NeedsReturn)
             }
         }
     }
@@ -82,34 +96,51 @@
         &mut self,
         size: u64,
         zero_init: bool,
-        kind: MiriMemoryKind,
     ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
         let this = self.eval_context_mut();
-        if size == 0 {
-            Ok(Pointer::null())
+        let align = this.malloc_align(size);
+        let ptr = this.allocate_ptr(Size::from_bytes(size), align, MiriMemoryKind::C.into())?;
+        if zero_init {
+            // We just allocated this, the access is definitely in-bounds and fits into our address space.
+            this.write_bytes_ptr(
+                ptr.into(),
+                iter::repeat(0u8).take(usize::try_from(size).unwrap()),
+            )
+            .unwrap();
+        }
+        Ok(ptr.into())
+    }
+
+    fn posix_memalign(
+        &mut self,
+        memptr: &OpTy<'tcx, Provenance>,
+        align: &OpTy<'tcx, Provenance>,
+        size: &OpTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx, Scalar<Provenance>> {
+        let this = self.eval_context_mut();
+        let memptr = this.deref_pointer(memptr)?;
+        let align = this.read_target_usize(align)?;
+        let size = this.read_target_usize(size)?;
+
+        // Align must be power of 2, and also at least ptr-sized (POSIX rules).
+        // But failure to adhere to this is not UB, it's an error condition.
+        if !align.is_power_of_two() || align < this.pointer_size().bytes() {
+            Ok(this.eval_libc("EINVAL"))
         } else {
-            let align = this.min_align(size, kind);
-            let ptr = this.allocate_ptr(Size::from_bytes(size), align, kind.into())?;
-            if zero_init {
-                // We just allocated this, the access is definitely in-bounds and fits into our address space.
-                this.write_bytes_ptr(
-                    ptr.into(),
-                    iter::repeat(0u8).take(usize::try_from(size).unwrap()),
-                )
-                .unwrap();
-            }
-            Ok(ptr.into())
+            let ptr = this.allocate_ptr(
+                Size::from_bytes(size),
+                Align::from_bytes(align).unwrap(),
+                MiriMemoryKind::C.into(),
+            )?;
+            this.write_pointer(ptr, &memptr)?;
+            Ok(Scalar::from_i32(0))
         }
     }
 
-    fn free(
-        &mut self,
-        ptr: Pointer<Option<Provenance>>,
-        kind: MiriMemoryKind,
-    ) -> InterpResult<'tcx> {
+    fn free(&mut self, ptr: Pointer<Option<Provenance>>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
         if !this.ptr_is_null(ptr)? {
-            this.deallocate_ptr(ptr, None, kind.into())?;
+            this.deallocate_ptr(ptr, None, MiriMemoryKind::C.into())?;
         }
         Ok(())
     }
@@ -118,19 +149,12 @@
         &mut self,
         old_ptr: Pointer<Option<Provenance>>,
         new_size: u64,
-        kind: MiriMemoryKind,
     ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
         let this = self.eval_context_mut();
-        let new_align = this.min_align(new_size, kind);
+        let new_align = this.malloc_align(new_size);
         if this.ptr_is_null(old_ptr)? {
             // Here we must behave like `malloc`.
-            if new_size == 0 {
-                Ok(Pointer::null())
-            } else {
-                let new_ptr =
-                    this.allocate_ptr(Size::from_bytes(new_size), new_align, kind.into())?;
-                Ok(new_ptr.into())
-            }
+            self.malloc(new_size, /*zero_init*/ false)
         } else {
             if new_size == 0 {
                 // C, in their infinite wisdom, made this UB.
@@ -142,10 +166,51 @@
                     None,
                     Size::from_bytes(new_size),
                     new_align,
-                    kind.into(),
+                    MiriMemoryKind::C.into(),
                 )?;
                 Ok(new_ptr.into())
             }
         }
     }
+
+    fn aligned_alloc(
+        &mut self,
+        align: &OpTy<'tcx, Provenance>,
+        size: &OpTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx, Pointer<Option<Provenance>>> {
+        let this = self.eval_context_mut();
+        let align = this.read_target_usize(align)?;
+        let size = this.read_target_usize(size)?;
+
+        // Alignment must be a power of 2, and "supported by the implementation".
+        // We decide that "supported by the implementation" means that the
+        // size must be a multiple of the alignment. (This restriction seems common
+        // enough that it is stated on <https://en.cppreference.com/w/c/memory/aligned_alloc>
+        // as a general rule, but the actual standard has no such rule.)
+        // If any of these are violated, we have to return NULL.
+        // All fundamental alignments must be supported.
+        //
+        // macOS and Illumos are buggy in that they require the alignment
+        // to be at least the size of a pointer, so they do not support all fundamental
+        // alignments. We do not emulate those platform bugs.
+        //
+        // Linux also sets errno to EINVAL, but that's non-standard behavior that we do not
+        // emulate.
+        // FreeBSD says some of these cases are UB but that's violating the C standard.
+        // http://en.cppreference.com/w/cpp/memory/c/aligned_alloc
+        // Linux: https://linux.die.net/man/3/aligned_alloc
+        // FreeBSD: https://man.freebsd.org/cgi/man.cgi?query=aligned_alloc&apropos=0&sektion=3&manpath=FreeBSD+9-current&format=html
+        match size.checked_rem(align) {
+            Some(0) if align.is_power_of_two() => {
+                let align = align.max(this.malloc_align(size).bytes());
+                let ptr = this.allocate_ptr(
+                    Size::from_bytes(size),
+                    Align::from_bytes(align).unwrap(),
+                    MiriMemoryKind::C.into(),
+                )?;
+                Ok(ptr.into())
+            }
+            _ => Ok(Pointer::null()),
+        }
+    }
 }
diff --git a/src/tools/miri/src/shims/extern_static.rs b/src/tools/miri/src/shims/extern_static.rs
index c3c7ef7..b9817a1 100644
--- a/src/tools/miri/src/shims/extern_static.rs
+++ b/src/tools/miri/src/shims/extern_static.rs
@@ -55,6 +55,12 @@
         let val = ImmTy::from_int(val, this.machine.layouts.u8);
         Self::alloc_extern_static(this, "__rust_alloc_error_handler_should_panic", val)?;
 
+        if this.target_os_is_unix() {
+            // "environ" is mandated by POSIX.
+            let environ = this.machine.env_vars.unix().environ();
+            Self::add_extern_static(this, "environ", environ);
+        }
+
         match this.tcx.sess.target.os.as_ref() {
             "linux" => {
                 Self::null_ptr_extern_statics(
@@ -62,19 +68,13 @@
                     &["__cxa_thread_atexit_impl", "__clock_gettime64"],
                 )?;
                 Self::weak_symbol_extern_statics(this, &["getrandom", "statx"])?;
-                // "environ"
-                let environ = this.machine.env_vars.unix().environ();
-                Self::add_extern_static(this, "environ", environ);
             }
             "freebsd" => {
                 Self::null_ptr_extern_statics(this, &["__cxa_thread_atexit_impl"])?;
-                // "environ"
-                let environ = this.machine.env_vars.unix().environ();
-                Self::add_extern_static(this, "environ", environ);
             }
             "android" => {
                 Self::null_ptr_extern_statics(this, &["bsd_signal"])?;
-                Self::weak_symbol_extern_statics(this, &["signal"])?;
+                Self::weak_symbol_extern_statics(this, &["signal", "getrandom"])?;
             }
             "windows" => {
                 // "_tls_used"
diff --git a/src/tools/miri/src/shims/ffi_support.rs b/src/tools/miri/src/shims/ffi_support.rs
deleted file mode 100644
index 6da119e..0000000
--- a/src/tools/miri/src/shims/ffi_support.rs
+++ /dev/null
@@ -1,289 +0,0 @@
-use libffi::{high::call as ffi, low::CodePtr};
-use std::ops::Deref;
-
-use rustc_middle::ty::{self as ty, IntTy, Ty, UintTy};
-use rustc_span::Symbol;
-use rustc_target::abi::HasDataLayout;
-
-use crate::*;
-
-impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
-
-pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
-    /// Extract the scalar value from the result of reading a scalar from the machine,
-    /// and convert it to a `CArg`.
-    fn scalar_to_carg(
-        k: Scalar<Provenance>,
-        arg_type: Ty<'tcx>,
-        cx: &impl HasDataLayout,
-    ) -> InterpResult<'tcx, CArg> {
-        match arg_type.kind() {
-            // If the primitive provided can be converted to a type matching the type pattern
-            // then create a `CArg` of this primitive value with the corresponding `CArg` constructor.
-            // the ints
-            ty::Int(IntTy::I8) => {
-                return Ok(CArg::Int8(k.to_i8()?));
-            }
-            ty::Int(IntTy::I16) => {
-                return Ok(CArg::Int16(k.to_i16()?));
-            }
-            ty::Int(IntTy::I32) => {
-                return Ok(CArg::Int32(k.to_i32()?));
-            }
-            ty::Int(IntTy::I64) => {
-                return Ok(CArg::Int64(k.to_i64()?));
-            }
-            ty::Int(IntTy::Isize) => {
-                // This will fail if host != target, but then the entire FFI thing probably won't work well
-                // in that situation.
-                return Ok(CArg::ISize(k.to_target_isize(cx)?.try_into().unwrap()));
-            }
-            // the uints
-            ty::Uint(UintTy::U8) => {
-                return Ok(CArg::UInt8(k.to_u8()?));
-            }
-            ty::Uint(UintTy::U16) => {
-                return Ok(CArg::UInt16(k.to_u16()?));
-            }
-            ty::Uint(UintTy::U32) => {
-                return Ok(CArg::UInt32(k.to_u32()?));
-            }
-            ty::Uint(UintTy::U64) => {
-                return Ok(CArg::UInt64(k.to_u64()?));
-            }
-            ty::Uint(UintTy::Usize) => {
-                // This will fail if host != target, but then the entire FFI thing probably won't work well
-                // in that situation.
-                return Ok(CArg::USize(k.to_target_usize(cx)?.try_into().unwrap()));
-            }
-            _ => {}
-        }
-        // If no primitives were returned then we have an unsupported type.
-        throw_unsup_format!(
-            "unsupported scalar argument type to external C function: {:?}",
-            arg_type
-        );
-    }
-
-    /// Call external C function and
-    /// store output, depending on return type in the function signature.
-    fn call_external_c_and_store_return<'a>(
-        &mut self,
-        link_name: Symbol,
-        dest: &MPlaceTy<'tcx, Provenance>,
-        ptr: CodePtr,
-        libffi_args: Vec<libffi::high::Arg<'a>>,
-    ) -> InterpResult<'tcx, ()> {
-        let this = self.eval_context_mut();
-
-        // Unsafe because of the call to external C code.
-        // Because this is calling a C function it is not necessarily sound,
-        // but there is no way around this and we've checked as much as we can.
-        unsafe {
-            // If the return type of a function is a primitive integer type,
-            // then call the function (`ptr`) with arguments `libffi_args`, store the return value as the specified
-            // primitive integer type, and then write this value out to the miri memory as an integer.
-            match dest.layout.ty.kind() {
-                // ints
-                ty::Int(IntTy::I8) => {
-                    let x = ffi::call::<i8>(ptr, libffi_args.as_slice());
-                    this.write_int(x, dest)?;
-                    return Ok(());
-                }
-                ty::Int(IntTy::I16) => {
-                    let x = ffi::call::<i16>(ptr, libffi_args.as_slice());
-                    this.write_int(x, dest)?;
-                    return Ok(());
-                }
-                ty::Int(IntTy::I32) => {
-                    let x = ffi::call::<i32>(ptr, libffi_args.as_slice());
-                    this.write_int(x, dest)?;
-                    return Ok(());
-                }
-                ty::Int(IntTy::I64) => {
-                    let x = ffi::call::<i64>(ptr, libffi_args.as_slice());
-                    this.write_int(x, dest)?;
-                    return Ok(());
-                }
-                ty::Int(IntTy::Isize) => {
-                    let x = ffi::call::<isize>(ptr, libffi_args.as_slice());
-                    // `isize` doesn't `impl Into<i128>`, so convert manually.
-                    // Convert to `i64` since this covers both 32- and 64-bit machines.
-                    this.write_int(i64::try_from(x).unwrap(), dest)?;
-                    return Ok(());
-                }
-                // uints
-                ty::Uint(UintTy::U8) => {
-                    let x = ffi::call::<u8>(ptr, libffi_args.as_slice());
-                    this.write_int(x, dest)?;
-                    return Ok(());
-                }
-                ty::Uint(UintTy::U16) => {
-                    let x = ffi::call::<u16>(ptr, libffi_args.as_slice());
-                    this.write_int(x, dest)?;
-                    return Ok(());
-                }
-                ty::Uint(UintTy::U32) => {
-                    let x = ffi::call::<u32>(ptr, libffi_args.as_slice());
-                    this.write_int(x, dest)?;
-                    return Ok(());
-                }
-                ty::Uint(UintTy::U64) => {
-                    let x = ffi::call::<u64>(ptr, libffi_args.as_slice());
-                    this.write_int(x, dest)?;
-                    return Ok(());
-                }
-                ty::Uint(UintTy::Usize) => {
-                    let x = ffi::call::<usize>(ptr, libffi_args.as_slice());
-                    // `usize` doesn't `impl Into<i128>`, so convert manually.
-                    // Convert to `u64` since this covers both 32- and 64-bit machines.
-                    this.write_int(u64::try_from(x).unwrap(), dest)?;
-                    return Ok(());
-                }
-                // Functions with no declared return type (i.e., the default return)
-                // have the output_type `Tuple([])`.
-                ty::Tuple(t_list) =>
-                    if t_list.len() == 0 {
-                        ffi::call::<()>(ptr, libffi_args.as_slice());
-                        return Ok(());
-                    },
-                _ => {}
-            }
-            // FIXME ellen! deal with all the other return types
-            throw_unsup_format!("unsupported return type to external C function: {:?}", link_name);
-        }
-    }
-
-    /// Get the pointer to the function of the specified name in the shared object file,
-    /// if it exists. The function must be in the shared object file specified: we do *not*
-    /// return pointers to functions in dependencies of the library.  
-    fn get_func_ptr_explicitly_from_lib(&mut self, link_name: Symbol) -> Option<CodePtr> {
-        let this = self.eval_context_mut();
-        // Try getting the function from the shared library.
-        // On windows `_lib_path` will be unused, hence the name starting with `_`.
-        let (lib, _lib_path) = this.machine.external_so_lib.as_ref().unwrap();
-        let func: libloading::Symbol<'_, unsafe extern "C" fn()> = unsafe {
-            match lib.get(link_name.as_str().as_bytes()) {
-                Ok(x) => x,
-                Err(_) => {
-                    return None;
-                }
-            }
-        };
-
-        // FIXME: this is a hack!
-        // The `libloading` crate will automatically load system libraries like `libc`.
-        // On linux `libloading` is based on `dlsym`: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#202
-        // and `dlsym`(https://linux.die.net/man/3/dlsym) looks through the dependency tree of the
-        // library if it can't find the symbol in the library itself.
-        // So, in order to check if the function was actually found in the specified
-        // `machine.external_so_lib` we need to check its `dli_fname` and compare it to
-        // the specified SO file path.
-        // This code is a reimplementation of the mechanism for getting `dli_fname` in `libloading`,
-        // from: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#411
-        // using the `libc` crate where this interface is public.
-        // No `libc::dladdr` on windows.
-        let mut info = std::mem::MaybeUninit::<libc::Dl_info>::uninit();
-        unsafe {
-            if libc::dladdr(*func.deref() as *const _, info.as_mut_ptr()) != 0 {
-                if std::ffi::CStr::from_ptr(info.assume_init().dli_fname).to_str().unwrap()
-                    != _lib_path.to_str().unwrap()
-                {
-                    return None;
-                }
-            }
-        }
-        // Return a pointer to the function.
-        Some(CodePtr(*func.deref() as *mut _))
-    }
-
-    /// Call specified external C function, with supplied arguments.
-    /// Need to convert all the arguments from their hir representations to
-    /// a form compatible with C (through `libffi` call).
-    /// Then, convert return from the C call into a corresponding form that
-    /// can be stored in Miri internal memory.
-    fn call_external_c_fct(
-        &mut self,
-        link_name: Symbol,
-        dest: &MPlaceTy<'tcx, Provenance>,
-        args: &[OpTy<'tcx, Provenance>],
-    ) -> InterpResult<'tcx, bool> {
-        // Get the pointer to the function in the shared object file if it exists.
-        let code_ptr = match self.get_func_ptr_explicitly_from_lib(link_name) {
-            Some(ptr) => ptr,
-            None => {
-                // Shared object file does not export this function -- try the shims next.
-                return Ok(false);
-            }
-        };
-
-        let this = self.eval_context_mut();
-
-        // Get the function arguments, and convert them to `libffi`-compatible form.
-        let mut libffi_args = Vec::<CArg>::with_capacity(args.len());
-        for cur_arg in args.iter() {
-            libffi_args.push(Self::scalar_to_carg(
-                this.read_scalar(cur_arg)?,
-                cur_arg.layout.ty,
-                this,
-            )?);
-        }
-
-        // Convert them to `libffi::high::Arg` type.
-        let libffi_args = libffi_args
-            .iter()
-            .map(|cur_arg| cur_arg.arg_downcast())
-            .collect::<Vec<libffi::high::Arg<'_>>>();
-
-        // Call the function and store output, depending on return type in the function signature.
-        self.call_external_c_and_store_return(link_name, dest, code_ptr, libffi_args)?;
-        Ok(true)
-    }
-}
-
-#[derive(Debug, Clone)]
-/// Enum of supported arguments to external C functions.
-// We introduce this enum instead of just calling `ffi::arg` and storing a list
-// of `libffi::high::Arg` directly, because the `libffi::high::Arg` just wraps a reference
-// to the value it represents: https://docs.rs/libffi/latest/libffi/high/call/struct.Arg.html
-// and we need to store a copy of the value, and pass a reference to this copy to C instead.
-pub enum CArg {
-    /// 8-bit signed integer.
-    Int8(i8),
-    /// 16-bit signed integer.
-    Int16(i16),
-    /// 32-bit signed integer.
-    Int32(i32),
-    /// 64-bit signed integer.
-    Int64(i64),
-    /// isize.
-    ISize(isize),
-    /// 8-bit unsigned integer.
-    UInt8(u8),
-    /// 16-bit unsigned integer.
-    UInt16(u16),
-    /// 32-bit unsigned integer.
-    UInt32(u32),
-    /// 64-bit unsigned integer.
-    UInt64(u64),
-    /// usize.
-    USize(usize),
-}
-
-impl<'a> CArg {
-    /// Convert a `CArg` to a `libffi` argument type.
-    fn arg_downcast(&'a self) -> libffi::high::Arg<'a> {
-        match self {
-            CArg::Int8(i) => ffi::arg(i),
-            CArg::Int16(i) => ffi::arg(i),
-            CArg::Int32(i) => ffi::arg(i),
-            CArg::Int64(i) => ffi::arg(i),
-            CArg::ISize(i) => ffi::arg(i),
-            CArg::UInt8(i) => ffi::arg(i),
-            CArg::UInt16(i) => ffi::arg(i),
-            CArg::UInt32(i) => ffi::arg(i),
-            CArg::UInt64(i) => ffi::arg(i),
-            CArg::USize(i) => ffi::arg(i),
-        }
-    }
-}
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index c51a27b..eccccb4 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -82,11 +82,15 @@
         }
 
         // The rest either implements the logic, or falls back to `lookup_exported_symbol`.
-        match this.emulate_foreign_item_inner(link_name, abi, args, dest, unwind)? {
-            EmulateItemResult::NeedsJumping => {
+        match this.emulate_foreign_item_inner(link_name, abi, args, dest)? {
+            EmulateItemResult::NeedsReturn => {
                 trace!("{:?}", this.dump_place(&dest.clone().into()));
                 this.return_to_block(ret)?;
             }
+            EmulateItemResult::NeedsUnwind => {
+                // Jump to the unwind block to begin unwinding.
+                this.unwind_to_block(unwind)?;
+            }
             EmulateItemResult::AlreadyJumped => (),
             EmulateItemResult::NotSupported => {
                 if let Some(body) = this.lookup_exported_symbol(link_name)? {
@@ -108,6 +112,7 @@
         let this = self.eval_context_ref();
         match this.tcx.sess.target.os.as_ref() {
             os if this.target_os_is_unix() => shims::unix::foreign_items::is_dyn_sym(name, os),
+            "wasi" => shims::wasi::foreign_items::is_dyn_sym(name),
             "windows" => shims::windows::foreign_items::is_dyn_sym(name),
             _ => false,
         }
@@ -205,19 +210,18 @@
         abi: Abi,
         args: &[OpTy<'tcx, Provenance>],
         dest: &MPlaceTy<'tcx, Provenance>,
-        unwind: mir::UnwindAction,
     ) -> InterpResult<'tcx, EmulateItemResult> {
         let this = self.eval_context_mut();
 
         // First deal with any external C functions in linked .so file.
         #[cfg(target_os = "linux")]
-        if this.machine.external_so_lib.as_ref().is_some() {
-            use crate::shims::ffi_support::EvalContextExt as _;
+        if this.machine.native_lib.as_ref().is_some() {
+            use crate::shims::native_lib::EvalContextExt as _;
             // An Ok(false) here means that the function being called was not exported
             // by the specified `.so` file; we should continue and check if it corresponds to
             // a provided shim.
-            if this.call_external_c_fct(link_name, dest, args)? {
-                return Ok(EmulateItemResult::NeedsJumping);
+            if this.call_native_fn(link_name, dest, args)? {
+                return Ok(EmulateItemResult::NeedsReturn);
             }
         }
 
@@ -262,9 +266,9 @@
         match link_name.as_str() {
             // Miri-specific extern functions
             "miri_start_unwind" => {
-                // `check_shim` happens inside `handle_miri_start_unwind`.
-                this.handle_miri_start_unwind(abi, link_name, args, unwind)?;
-                return Ok(EmulateItemResult::AlreadyJumped);
+                let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?;
+                this.handle_miri_start_unwind(payload)?;
+                return Ok(EmulateItemResult::NeedsUnwind);
             }
             "miri_run_provenance_gc" => {
                 let [] = this.check_shim(abi, Abi::Rust, link_name, args)?;
@@ -421,7 +425,7 @@
             "malloc" => {
                 let [size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let size = this.read_target_usize(size)?;
-                let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C)?;
+                let res = this.malloc(size, /*zero_init:*/ false)?;
                 this.write_pointer(res, dest)?;
             }
             "calloc" => {
@@ -432,20 +436,20 @@
                 let size = items
                     .checked_mul(len)
                     .ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?;
-                let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C)?;
+                let res = this.malloc(size, /*zero_init:*/ true)?;
                 this.write_pointer(res, dest)?;
             }
             "free" => {
                 let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
-                this.free(ptr, MiriMemoryKind::C)?;
+                this.free(ptr)?;
             }
             "realloc" => {
                 let [old_ptr, new_size] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 let old_ptr = this.read_pointer(old_ptr)?;
                 let new_size = this.read_target_usize(new_size)?;
-                let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?;
+                let res = this.realloc(old_ptr, new_size)?;
                 this.write_pointer(res, dest)?;
             }
 
@@ -479,7 +483,7 @@
                     "__rust_alloc" => return this.emulate_allocator(default),
                     "miri_alloc" => {
                         default(this)?;
-                        return Ok(EmulateItemResult::NeedsJumping);
+                        return Ok(EmulateItemResult::NeedsReturn);
                     }
                     _ => unreachable!(),
                 }
@@ -539,7 +543,7 @@
                     }
                     "miri_dealloc" => {
                         default(this)?;
-                        return Ok(EmulateItemResult::NeedsJumping);
+                        return Ok(EmulateItemResult::NeedsReturn);
                     }
                     _ => unreachable!(),
                 }
@@ -657,6 +661,16 @@
                     dest,
                 )?;
             }
+            "wcslen" => {
+                let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let ptr = this.read_pointer(ptr)?;
+                // This reads at least 1 byte, so we are already enforcing that this is a valid pointer.
+                let n = this.read_wchar_t_str(ptr)?.len();
+                this.write_scalar(
+                    Scalar::from_target_usize(u64::try_from(n).unwrap(), this),
+                    dest,
+                )?;
+            }
             "memcpy" => {
                 let [ptr_dest, ptr_src, n] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
@@ -937,6 +951,10 @@
                         shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_inner(
                             this, link_name, abi, args, dest,
                         ),
+                    "wasi" =>
+                        shims::wasi::foreign_items::EvalContextExt::emulate_foreign_item_inner(
+                            this, link_name, abi, args, dest,
+                        ),
                     "windows" =>
                         shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_inner(
                             this, link_name, abi, args, dest,
@@ -946,6 +964,6 @@
         };
         // We only fall through to here if we did *not* hit the `_` arm above,
         // i.e., if we actually emulated the function with one of the shims.
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/mod.rs b/src/tools/miri/src/shims/mod.rs
index 1104845..a41a288 100644
--- a/src/tools/miri/src/shims/mod.rs
+++ b/src/tools/miri/src/shims/mod.rs
@@ -3,24 +3,29 @@
 mod alloc;
 mod backtrace;
 #[cfg(target_os = "linux")]
-pub mod ffi_support;
-pub mod foreign_items;
-pub mod unix;
-pub mod windows;
+mod native_lib;
+mod unix;
+mod wasi;
+mod windows;
 mod x86;
 
 pub mod env;
 pub mod extern_static;
+pub mod foreign_items;
 pub mod os_str;
 pub mod panic;
 pub mod time;
 pub mod tls;
 
+pub use unix::{DirTable, FdTable};
+
 /// What needs to be done after emulating an item (a shim or an intrinsic) is done.
 pub enum EmulateItemResult {
     /// The caller is expected to jump to the return block.
-    NeedsJumping,
-    /// Jumping has already been taken care of.
+    NeedsReturn,
+    /// The caller is expected to jump to the unwind block.
+    NeedsUnwind,
+    /// Jumping to the next block has already been taken care of.
     AlreadyJumped,
     /// The item is not supported.
     NotSupported,
diff --git a/src/tools/miri/src/shims/native_lib.rs b/src/tools/miri/src/shims/native_lib.rs
new file mode 100644
index 0000000..f9b8563
--- /dev/null
+++ b/src/tools/miri/src/shims/native_lib.rs
@@ -0,0 +1,242 @@
+//! Implements calling functions from a native library.
+use libffi::{high::call as ffi, low::CodePtr};
+use std::ops::Deref;
+
+use rustc_middle::ty::{self as ty, IntTy, UintTy};
+use rustc_span::Symbol;
+use rustc_target::abi::{Abi, HasDataLayout};
+
+use crate::*;
+
+impl<'mir, 'tcx: 'mir> EvalContextExtPriv<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
+trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
+    /// Call native host function and return the output as an immediate.
+    fn call_native_with_args<'a>(
+        &mut self,
+        link_name: Symbol,
+        dest: &MPlaceTy<'tcx, Provenance>,
+        ptr: CodePtr,
+        libffi_args: Vec<libffi::high::Arg<'a>>,
+    ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> {
+        let this = self.eval_context_mut();
+
+        // Call the function (`ptr`) with arguments `libffi_args`, and obtain the return value
+        // as the specified primitive integer type
+        let scalar = match dest.layout.ty.kind() {
+            // ints
+            ty::Int(IntTy::I8) => {
+                // Unsafe because of the call to native code.
+                // Because this is calling a C function it is not necessarily sound,
+                // but there is no way around this and we've checked as much as we can.
+                let x = unsafe { ffi::call::<i8>(ptr, libffi_args.as_slice()) };
+                Scalar::from_i8(x)
+            }
+            ty::Int(IntTy::I16) => {
+                let x = unsafe { ffi::call::<i16>(ptr, libffi_args.as_slice()) };
+                Scalar::from_i16(x)
+            }
+            ty::Int(IntTy::I32) => {
+                let x = unsafe { ffi::call::<i32>(ptr, libffi_args.as_slice()) };
+                Scalar::from_i32(x)
+            }
+            ty::Int(IntTy::I64) => {
+                let x = unsafe { ffi::call::<i64>(ptr, libffi_args.as_slice()) };
+                Scalar::from_i64(x)
+            }
+            ty::Int(IntTy::Isize) => {
+                let x = unsafe { ffi::call::<isize>(ptr, libffi_args.as_slice()) };
+                Scalar::from_target_isize(x.try_into().unwrap(), this)
+            }
+            // uints
+            ty::Uint(UintTy::U8) => {
+                let x = unsafe { ffi::call::<u8>(ptr, libffi_args.as_slice()) };
+                Scalar::from_u8(x)
+            }
+            ty::Uint(UintTy::U16) => {
+                let x = unsafe { ffi::call::<u16>(ptr, libffi_args.as_slice()) };
+                Scalar::from_u16(x)
+            }
+            ty::Uint(UintTy::U32) => {
+                let x = unsafe { ffi::call::<u32>(ptr, libffi_args.as_slice()) };
+                Scalar::from_u32(x)
+            }
+            ty::Uint(UintTy::U64) => {
+                let x = unsafe { ffi::call::<u64>(ptr, libffi_args.as_slice()) };
+                Scalar::from_u64(x)
+            }
+            ty::Uint(UintTy::Usize) => {
+                let x = unsafe { ffi::call::<usize>(ptr, libffi_args.as_slice()) };
+                Scalar::from_target_usize(x.try_into().unwrap(), this)
+            }
+            // Functions with no declared return type (i.e., the default return)
+            // have the output_type `Tuple([])`.
+            ty::Tuple(t_list) if t_list.len() == 0 => {
+                unsafe { ffi::call::<()>(ptr, libffi_args.as_slice()) };
+                return Ok(ImmTy::uninit(dest.layout));
+            }
+            _ => throw_unsup_format!("unsupported return type for native call: {:?}", link_name),
+        };
+        Ok(ImmTy::from_scalar(scalar, dest.layout))
+    }
+
+    /// Get the pointer to the function of the specified name in the shared object file,
+    /// if it exists. The function must be in the shared object file specified: we do *not*
+    /// return pointers to functions in dependencies of the library.  
+    fn get_func_ptr_explicitly_from_lib(&mut self, link_name: Symbol) -> Option<CodePtr> {
+        let this = self.eval_context_mut();
+        // Try getting the function from the shared library.
+        // On windows `_lib_path` will be unused, hence the name starting with `_`.
+        let (lib, _lib_path) = this.machine.native_lib.as_ref().unwrap();
+        let func: libloading::Symbol<'_, unsafe extern "C" fn()> = unsafe {
+            match lib.get(link_name.as_str().as_bytes()) {
+                Ok(x) => x,
+                Err(_) => {
+                    return None;
+                }
+            }
+        };
+
+        // FIXME: this is a hack!
+        // The `libloading` crate will automatically load system libraries like `libc`.
+        // On linux `libloading` is based on `dlsym`: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#202
+        // and `dlsym`(https://linux.die.net/man/3/dlsym) looks through the dependency tree of the
+        // library if it can't find the symbol in the library itself.
+        // So, in order to check if the function was actually found in the specified
+        // `machine.external_so_lib` we need to check its `dli_fname` and compare it to
+        // the specified SO file path.
+        // This code is a reimplementation of the mechanism for getting `dli_fname` in `libloading`,
+        // from: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#411
+        // using the `libc` crate where this interface is public.
+        let mut info = std::mem::MaybeUninit::<libc::Dl_info>::uninit();
+        unsafe {
+            if libc::dladdr(*func.deref() as *const _, info.as_mut_ptr()) != 0 {
+                if std::ffi::CStr::from_ptr(info.assume_init().dli_fname).to_str().unwrap()
+                    != _lib_path.to_str().unwrap()
+                {
+                    return None;
+                }
+            }
+        }
+        // Return a pointer to the function.
+        Some(CodePtr(*func.deref() as *mut _))
+    }
+}
+
+impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
+pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
+    /// Call the native host function, with supplied arguments.
+    /// Needs to convert all the arguments from their Miri representations to
+    /// a native form (through `libffi` call).
+    /// Then, convert the return value from the native form into something that
+    /// can be stored in Miri's internal memory.
+    fn call_native_fn(
+        &mut self,
+        link_name: Symbol,
+        dest: &MPlaceTy<'tcx, Provenance>,
+        args: &[OpTy<'tcx, Provenance>],
+    ) -> InterpResult<'tcx, bool> {
+        let this = self.eval_context_mut();
+        // Get the pointer to the function in the shared object file if it exists.
+        let code_ptr = match this.get_func_ptr_explicitly_from_lib(link_name) {
+            Some(ptr) => ptr,
+            None => {
+                // Shared object file does not export this function -- try the shims next.
+                return Ok(false);
+            }
+        };
+
+        // Get the function arguments, and convert them to `libffi`-compatible form.
+        let mut libffi_args = Vec::<CArg>::with_capacity(args.len());
+        for arg in args.iter() {
+            if !matches!(arg.layout.abi, Abi::Scalar(_)) {
+                throw_unsup_format!("only scalar argument types are support for native calls")
+            }
+            libffi_args.push(imm_to_carg(this.read_immediate(arg)?, this)?);
+        }
+
+        // Convert them to `libffi::high::Arg` type.
+        let libffi_args = libffi_args
+            .iter()
+            .map(|arg| arg.arg_downcast())
+            .collect::<Vec<libffi::high::Arg<'_>>>();
+
+        // Call the function and store output, depending on return type in the function signature.
+        let ret = this.call_native_with_args(link_name, dest, code_ptr, libffi_args)?;
+        this.write_immediate(*ret, dest)?;
+        Ok(true)
+    }
+}
+
+#[derive(Debug, Clone)]
+/// Enum of supported arguments to external C functions.
+// We introduce this enum instead of just calling `ffi::arg` and storing a list
+// of `libffi::high::Arg` directly, because the `libffi::high::Arg` just wraps a reference
+// to the value it represents: https://docs.rs/libffi/latest/libffi/high/call/struct.Arg.html
+// and we need to store a copy of the value, and pass a reference to this copy to C instead.
+enum CArg {
+    /// 8-bit signed integer.
+    Int8(i8),
+    /// 16-bit signed integer.
+    Int16(i16),
+    /// 32-bit signed integer.
+    Int32(i32),
+    /// 64-bit signed integer.
+    Int64(i64),
+    /// isize.
+    ISize(isize),
+    /// 8-bit unsigned integer.
+    UInt8(u8),
+    /// 16-bit unsigned integer.
+    UInt16(u16),
+    /// 32-bit unsigned integer.
+    UInt32(u32),
+    /// 64-bit unsigned integer.
+    UInt64(u64),
+    /// usize.
+    USize(usize),
+}
+
+impl<'a> CArg {
+    /// Convert a `CArg` to a `libffi` argument type.
+    fn arg_downcast(&'a self) -> libffi::high::Arg<'a> {
+        match self {
+            CArg::Int8(i) => ffi::arg(i),
+            CArg::Int16(i) => ffi::arg(i),
+            CArg::Int32(i) => ffi::arg(i),
+            CArg::Int64(i) => ffi::arg(i),
+            CArg::ISize(i) => ffi::arg(i),
+            CArg::UInt8(i) => ffi::arg(i),
+            CArg::UInt16(i) => ffi::arg(i),
+            CArg::UInt32(i) => ffi::arg(i),
+            CArg::UInt64(i) => ffi::arg(i),
+            CArg::USize(i) => ffi::arg(i),
+        }
+    }
+}
+
+/// Extract the scalar value from the result of reading a scalar from the machine,
+/// and convert it to a `CArg`.
+fn imm_to_carg<'tcx>(
+    v: ImmTy<'tcx, Provenance>,
+    cx: &impl HasDataLayout,
+) -> InterpResult<'tcx, CArg> {
+    Ok(match v.layout.ty.kind() {
+        // If the primitive provided can be converted to a type matching the type pattern
+        // then create a `CArg` of this primitive value with the corresponding `CArg` constructor.
+        // the ints
+        ty::Int(IntTy::I8) => CArg::Int8(v.to_scalar().to_i8()?),
+        ty::Int(IntTy::I16) => CArg::Int16(v.to_scalar().to_i16()?),
+        ty::Int(IntTy::I32) => CArg::Int32(v.to_scalar().to_i32()?),
+        ty::Int(IntTy::I64) => CArg::Int64(v.to_scalar().to_i64()?),
+        ty::Int(IntTy::Isize) =>
+            CArg::ISize(v.to_scalar().to_target_isize(cx)?.try_into().unwrap()),
+        // the uints
+        ty::Uint(UintTy::U8) => CArg::UInt8(v.to_scalar().to_u8()?),
+        ty::Uint(UintTy::U16) => CArg::UInt16(v.to_scalar().to_u16()?),
+        ty::Uint(UintTy::U32) => CArg::UInt32(v.to_scalar().to_u32()?),
+        ty::Uint(UintTy::U64) => CArg::UInt64(v.to_scalar().to_u64()?),
+        ty::Uint(UintTy::Usize) =>
+            CArg::USize(v.to_scalar().to_target_usize(cx)?.try_into().unwrap()),
+        _ => throw_unsup_format!("unsupported argument type for native call: {}", v.layout.ty),
+    })
+}
diff --git a/src/tools/miri/src/shims/panic.rs b/src/tools/miri/src/shims/panic.rs
index 4444d29..e0e5396 100644
--- a/src/tools/miri/src/shims/panic.rs
+++ b/src/tools/miri/src/shims/panic.rs
@@ -13,7 +13,6 @@
 
 use rustc_ast::Mutability;
 use rustc_middle::{mir, ty};
-use rustc_span::Symbol;
 use rustc_target::spec::abi::Abi;
 use rustc_target::spec::PanicStrategy;
 
@@ -46,25 +45,15 @@
 pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
     /// Handles the special `miri_start_unwind` intrinsic, which is called
     /// by libpanic_unwind to delegate the actual unwinding process to Miri.
-    fn handle_miri_start_unwind(
-        &mut self,
-        abi: Abi,
-        link_name: Symbol,
-        args: &[OpTy<'tcx, Provenance>],
-        unwind: mir::UnwindAction,
-    ) -> InterpResult<'tcx> {
+    fn handle_miri_start_unwind(&mut self, payload: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> {
         let this = self.eval_context_mut();
 
         trace!("miri_start_unwind: {:?}", this.frame().instance);
 
-        // Get the raw pointer stored in arg[0] (the panic payload).
-        let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?;
         let payload = this.read_scalar(payload)?;
         let thread = this.active_thread_mut();
         thread.panic_payloads.push(payload);
 
-        // Jump to the unwind block to begin unwinding.
-        this.unwind_to_block(unwind)?;
         Ok(())
     }
 
diff --git a/src/tools/miri/src/shims/unix/android/foreign_items.rs b/src/tools/miri/src/shims/unix/android/foreign_items.rs
new file mode 100644
index 0000000..590a567
--- /dev/null
+++ b/src/tools/miri/src/shims/unix/android/foreign_items.rs
@@ -0,0 +1,32 @@
+use rustc_span::Symbol;
+use rustc_target::spec::abi::Abi;
+
+use crate::*;
+
+pub fn is_dyn_sym(_name: &str) -> bool {
+    false
+}
+
+impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
+pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
+    fn emulate_foreign_item_inner(
+        &mut self,
+        link_name: Symbol,
+        abi: Abi,
+        args: &[OpTy<'tcx, Provenance>],
+        dest: &MPlaceTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx, EmulateItemResult> {
+        let this = self.eval_context_mut();
+        match link_name.as_str() {
+            // Miscellaneous
+            "__errno" => {
+                let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let errno_place = this.last_error_place()?;
+                this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
+            }
+
+            _ => return Ok(EmulateItemResult::NotSupported),
+        }
+        Ok(EmulateItemResult::NeedsReturn)
+    }
+}
diff --git a/src/tools/miri/src/shims/unix/android/mod.rs b/src/tools/miri/src/shims/unix/android/mod.rs
new file mode 100644
index 0000000..09c6507
--- /dev/null
+++ b/src/tools/miri/src/shims/unix/android/mod.rs
@@ -0,0 +1 @@
+pub mod foreign_items;
diff --git a/src/tools/miri/src/shims/unix/env.rs b/src/tools/miri/src/shims/unix/env.rs
index 9082d13..6fcfb69 100644
--- a/src/tools/miri/src/shims/unix/env.rs
+++ b/src/tools/miri/src/shims/unix/env.rs
@@ -228,7 +228,7 @@
 
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`getcwd`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
+            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
             return Ok(Pointer::null());
         }
 
@@ -241,7 +241,7 @@
                 let erange = this.eval_libc("ERANGE");
                 this.set_last_error(erange)?;
             }
-            Err(e) => this.set_last_error_from_io_error(e.kind())?,
+            Err(e) => this.set_last_error_from_io_error(e)?,
         }
 
         Ok(Pointer::null())
@@ -255,7 +255,7 @@
 
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`chdir`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
+            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
 
             return Ok(-1);
         }
@@ -263,7 +263,7 @@
         match env::set_current_dir(path) {
             Ok(()) => Ok(0),
             Err(e) => {
-                this.set_last_error_from_io_error(e.kind())?;
+                this.set_last_error_from_io_error(e)?;
                 Ok(-1)
             }
         }
diff --git a/src/tools/miri/src/shims/unix/fd.rs b/src/tools/miri/src/shims/unix/fd.rs
index e536b78..8159960 100644
--- a/src/tools/miri/src/shims/unix/fd.rs
+++ b/src/tools/miri/src/shims/unix/fd.rs
@@ -7,7 +7,6 @@
 use std::io::{self, ErrorKind, IsTerminal, Read, SeekFrom, Write};
 use std::rc::Rc;
 
-use rustc_middle::ty::TyCtxt;
 use rustc_target::abi::Size;
 
 use crate::shims::unix::*;
@@ -22,7 +21,7 @@
         &mut self,
         _communicate_allowed: bool,
         _bytes: &mut [u8],
-        _tcx: TyCtxt<'tcx>,
+        _ecx: &mut MiriInterpCx<'_, 'tcx>,
     ) -> InterpResult<'tcx, io::Result<usize>> {
         throw_unsup_format!("cannot read from {}", self.name());
     }
@@ -32,7 +31,7 @@
         &mut self,
         _communicate_allowed: bool,
         _bytes: &[u8],
-        _tcx: TyCtxt<'tcx>,
+        _ecx: &mut MiriInterpCx<'_, 'tcx>,
     ) -> InterpResult<'tcx, io::Result<usize>> {
         throw_unsup_format!("cannot write to {}", self.name());
     }
@@ -82,7 +81,7 @@
         &mut self,
         communicate_allowed: bool,
         bytes: &mut [u8],
-        _tcx: TyCtxt<'tcx>,
+        _ecx: &mut MiriInterpCx<'_, 'tcx>,
     ) -> InterpResult<'tcx, io::Result<usize>> {
         if !communicate_allowed {
             // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin.
@@ -105,7 +104,7 @@
         &mut self,
         _communicate_allowed: bool,
         bytes: &[u8],
-        _tcx: TyCtxt<'tcx>,
+        _ecx: &mut MiriInterpCx<'_, 'tcx>,
     ) -> InterpResult<'tcx, io::Result<usize>> {
         // We allow writing to stderr even with isolation enabled.
         let result = Write::write(self, bytes);
@@ -133,7 +132,7 @@
         &mut self,
         _communicate_allowed: bool,
         bytes: &[u8],
-        _tcx: TyCtxt<'tcx>,
+        _ecx: &mut MiriInterpCx<'_, 'tcx>,
     ) -> InterpResult<'tcx, io::Result<usize>> {
         // We allow writing to stderr even with isolation enabled.
         // No need to flush, stderr is not buffered.
@@ -158,7 +157,7 @@
         &mut self,
         _communicate_allowed: bool,
         bytes: &[u8],
-        _tcx: TyCtxt<'tcx>,
+        _ecx: &mut MiriInterpCx<'_, 'tcx>,
     ) -> InterpResult<'tcx, io::Result<usize>> {
         // We just don't write anything, but report to the user that we did.
         Ok(Ok(bytes.len()))
@@ -173,6 +172,14 @@
         FileDescriptor(Rc::new(RefCell::new(Box::new(fd))))
     }
 
+    pub fn borrow(&self) -> Ref<'_, dyn FileDescription> {
+        Ref::map(self.0.borrow(), |fd| fd.as_ref())
+    }
+
+    pub fn borrow_mut(&self) -> RefMut<'_, dyn FileDescription> {
+        RefMut::map(self.0.borrow_mut(), |fd| fd.as_mut())
+    }
+
     pub fn close<'ctx>(self, communicate_allowed: bool) -> InterpResult<'ctx, io::Result<()>> {
         // Destroy this `Rc` using `into_inner` so we can call `close` instead of
         // implicitly running the destructor of the file description.
@@ -242,12 +249,12 @@
 
     pub fn get(&self, fd: i32) -> Option<Ref<'_, dyn FileDescription>> {
         let fd = self.fds.get(&fd)?;
-        Some(Ref::map(fd.0.borrow(), |fd| fd.as_ref()))
+        Some(fd.borrow())
     }
 
     pub fn get_mut(&self, fd: i32) -> Option<RefMut<'_, dyn FileDescription>> {
         let fd = self.fds.get(&fd)?;
-        Some(RefMut::map(fd.0.borrow_mut(), |fd| fd.as_mut()))
+        Some(fd.borrow_mut())
     }
 
     pub fn dup(&self, fd: i32) -> Option<FileDescriptor> {
@@ -312,7 +319,7 @@
             // Reject if isolation is enabled.
             if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
                 this.reject_in_isolation("`fcntl`", reject_with)?;
-                this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
+                this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
                 return Ok(-1);
             }
 
@@ -370,7 +377,8 @@
             .min(u64::try_from(isize::MAX).unwrap());
         let communicate = this.machine.communicate();
 
-        let Some(mut file_descriptor) = this.machine.fds.get_mut(fd) else {
+        // We temporarily dup the FD to be able to retain mutable access to `this`.
+        let Some(file_descriptor) = this.machine.fds.dup(fd) else {
             trace!("read: FD not found");
             return this.fd_not_found();
         };
@@ -383,7 +391,8 @@
         // `File::read` never returns a value larger than `count`,
         // so this cannot fail.
         let result = file_descriptor
-            .read(communicate, &mut bytes, *this.tcx)?
+            .borrow_mut()
+            .read(communicate, &mut bytes, this)?
             .map(|c| i64::try_from(c).unwrap());
         drop(file_descriptor);
 
@@ -394,7 +403,7 @@
                 Ok(read_bytes)
             }
             Err(e) => {
-                this.set_last_error_from_io_error(e.kind())?;
+                this.set_last_error_from_io_error(e)?;
                 Ok(-1)
             }
         }
@@ -421,12 +430,14 @@
         let communicate = this.machine.communicate();
 
         let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?.to_owned();
-        let Some(mut file_descriptor) = this.machine.fds.get_mut(fd) else {
+        // We temporarily dup the FD to be able to retain mutable access to `this`.
+        let Some(file_descriptor) = this.machine.fds.dup(fd) else {
             return this.fd_not_found();
         };
 
         let result = file_descriptor
-            .write(communicate, &bytes, *this.tcx)?
+            .borrow_mut()
+            .write(communicate, &bytes, this)?
             .map(|c| i64::try_from(c).unwrap());
         drop(file_descriptor);
 
diff --git a/src/tools/miri/src/shims/unix/foreign_items.rs b/src/tools/miri/src/shims/unix/foreign_items.rs
index 595cf64..86dd23f 100644
--- a/src/tools/miri/src/shims/unix/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/foreign_items.rs
@@ -3,13 +3,13 @@
 
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_span::Symbol;
-use rustc_target::abi::{Align, Size};
 use rustc_target::spec::abi::Abi;
 
 use crate::shims::alloc::EvalContextExt as _;
 use crate::shims::unix::*;
 use crate::*;
 
+use shims::unix::android::foreign_items as android;
 use shims::unix::freebsd::foreign_items as freebsd;
 use shims::unix::linux::foreign_items as linux;
 use shims::unix::macos::foreign_items as macos;
@@ -27,6 +27,7 @@
         // Give specific OSes a chance to allow their symbols.
         _ =>
             match target_os {
+                "android" => android::is_dyn_sym(name),
                 "freebsd" => freebsd::is_dyn_sym(name),
                 "linux" => linux::is_dyn_sym(name),
                 "macos" => macos::is_dyn_sym(name),
@@ -249,28 +250,9 @@
 
             // Allocation
             "posix_memalign" => {
-                let [ret, align, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
-                let ret = this.deref_pointer(ret)?;
-                let align = this.read_target_usize(align)?;
-                let size = this.read_target_usize(size)?;
-                // Align must be power of 2, and also at least ptr-sized (POSIX rules).
-                // But failure to adhere to this is not UB, it's an error condition.
-                if !align.is_power_of_two() || align < this.pointer_size().bytes() {
-                    let einval = this.eval_libc_i32("EINVAL");
-                    this.write_int(einval, dest)?;
-                } else {
-                    if size == 0 {
-                        this.write_null(&ret)?;
-                    } else {
-                        let ptr = this.allocate_ptr(
-                            Size::from_bytes(size),
-                            Align::from_bytes(align).unwrap(),
-                            MiriMemoryKind::C.into(),
-                        )?;
-                        this.write_pointer(ptr, &ret)?;
-                    }
-                    this.write_null(dest)?;
-                }
+                let [memptr, align, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let result = this.posix_memalign(memptr, align, size)?;
+                this.write_scalar(result, dest)?;
             }
 
             "mmap" => {
@@ -287,7 +269,7 @@
 
             "reallocarray" => {
                 // Currently this function does not exist on all Unixes, e.g. on macOS.
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd") {
+                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "android") {
                     throw_unsup_format!(
                         "`reallocarray` is not supported on {}",
                         this.tcx.sess.target.os
@@ -310,11 +292,19 @@
                         this.write_null(dest)?;
                     }
                     Some(len) => {
-                        let res = this.realloc(ptr, len, MiriMemoryKind::C)?;
+                        let res = this.realloc(ptr, len)?;
                         this.write_pointer(res, dest)?;
                     }
                 }
             }
+            "aligned_alloc" => {
+                // This is a C11 function, we assume all Unixes have it.
+                // (MSVC explicitly does not support this.)
+                let [align, size] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let res = this.aligned_alloc(align, size)?;
+                this.write_pointer(res, dest)?;
+            }
 
             // Dynamic symbol loading
             "dlsym" => {
@@ -378,8 +368,7 @@
                     .builtin_deref(true)
                     .ok_or_else(|| err_ub_format!(
                         "wrong signature used for `pthread_key_create`: first argument must be a raw pointer."
-                    ))?
-                    .ty;
+                    ))?;
                 let key_layout = this.layout_of(key_type)?;
 
                 // Create key and write it into the memory where `key_ptr` wants it.
@@ -606,7 +595,7 @@
             "getentropy" => {
                 // This function is non-standard but exists with the same signature and behavior on
                 // Linux, macOS, FreeBSD and Solaris/Illumos.
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "freebsd" | "illumos" | "solaris") {
+                if !matches!(&*this.tcx.sess.target.os, "linux" | "macos" | "freebsd" | "illumos" | "solaris" | "android") {
                     throw_unsup_format!(
                         "`getentropy` is not supported on {}",
                         this.tcx.sess.target.os
@@ -635,9 +624,9 @@
             "getrandom" => {
                 // This function is non-standard but exists with the same signature and behavior on
                 // Linux, FreeBSD and Solaris/Illumos.
-                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "illumos" | "solaris") {
+                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "illumos" | "solaris" | "android") {
                     throw_unsup_format!(
-                        "`getentropy` is not supported on {}",
+                        "`getrandom` is not supported on {}",
                         this.tcx.sess.target.os
                     );
                 }
@@ -650,6 +639,31 @@
                 this.gen_random(ptr, len)?;
                 this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
             }
+            "_Unwind_RaiseException" => {
+                // This is not formally part of POSIX, but it is very wide-spread on POSIX systems.
+                // It was originally specified as part of the Itanium C++ ABI:
+                // https://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#base-throw.
+                // On Linux it is
+                // documented as part of the LSB:
+                // https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/baselib--unwind-raiseexception.html
+                // Basically every other UNIX uses the exact same api though. Arm also references
+                // back to the Itanium C++ ABI for the definition of `_Unwind_RaiseException` for
+                // arm64:
+                // https://github.com/ARM-software/abi-aa/blob/main/cppabi64/cppabi64.rst#toc-entry-35
+                // For arm32 they did something custom, but similar enough that the same
+                // `_Unwind_RaiseException` impl in miri should work:
+                // https://github.com/ARM-software/abi-aa/blob/main/ehabi32/ehabi32.rst
+                if !matches!(&*this.tcx.sess.target.os, "linux" | "freebsd" | "illumos" | "solaris" | "android" | "macos") {
+                    throw_unsup_format!(
+                        "`_Unwind_RaiseException` is not supported on {}",
+                        this.tcx.sess.target.os
+                    );
+                }
+                // This function looks and behaves excatly like miri_start_unwind.
+                let [payload] = this.check_shim(abi, Abi::C { unwind: true }, link_name, args)?;
+                this.handle_miri_start_unwind(payload)?;
+                return Ok(EmulateItemResult::NeedsUnwind);
+            }
 
             // Incomplete shims that we "stub out" just to get pre-main initialization code to work.
             // These shims are enabled only when the caller is in the standard library.
@@ -719,8 +733,9 @@
                 this.write_int(super::UID, dest)?;
             }
 
-            "getpwuid_r"
+            "getpwuid_r" | "__posix_getpwuid_r"
             if this.frame_in_std() => {
+                // getpwuid_r is the standard name, __posix_getpwuid_r is used on solarish
                 let [uid, pwd, buf, buflen, result] =
                     this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
                 this.check_no_isolation("`getpwuid_r`")?;
@@ -760,6 +775,7 @@
             _ => {
                 let target_os = &*this.tcx.sess.target.os;
                 return match target_os {
+                    "android" => android::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
                     "freebsd" => freebsd::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
                     "linux" => linux::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
                     "macos" => macos::EvalContextExt::emulate_foreign_item_inner(this, link_name, abi, args, dest),
@@ -769,6 +785,6 @@
             }
         };
 
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
index e70cd35..8a7f7e9 100644
--- a/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/freebsd/foreign_items.rs
@@ -86,6 +86,6 @@
 
             _ => return Ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index 0587479..82bc495 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -9,7 +9,6 @@
 use std::time::SystemTime;
 
 use rustc_data_structures::fx::FxHashMap;
-use rustc_middle::ty::TyCtxt;
 use rustc_target::abi::Size;
 
 use crate::shims::os_str::bytes_to_os_str;
@@ -34,7 +33,7 @@
         &mut self,
         communicate_allowed: bool,
         bytes: &mut [u8],
-        _tcx: TyCtxt<'tcx>,
+        _ecx: &mut MiriInterpCx<'_, 'tcx>,
     ) -> InterpResult<'tcx, io::Result<usize>> {
         assert!(communicate_allowed, "isolation should have prevented even opening a file");
         Ok(self.file.read(bytes))
@@ -44,7 +43,7 @@
         &mut self,
         communicate_allowed: bool,
         bytes: &[u8],
-        _tcx: TyCtxt<'tcx>,
+        _ecx: &mut MiriInterpCx<'_, 'tcx>,
     ) -> InterpResult<'tcx, io::Result<usize>> {
         assert!(communicate_allowed, "isolation should have prevented even opening a file");
         Ok(self.file.write(bytes))
@@ -137,37 +136,28 @@
         &mut self,
         file_type: std::io::Result<FileType>,
     ) -> InterpResult<'tcx, i32> {
+        #[cfg(unix)]
+        use std::os::unix::fs::FileTypeExt;
+
         let this = self.eval_context_mut();
         match file_type {
             Ok(file_type) => {
-                if file_type.is_dir() {
-                    Ok(this.eval_libc("DT_DIR").to_u8()?.into())
-                } else if file_type.is_file() {
-                    Ok(this.eval_libc("DT_REG").to_u8()?.into())
-                } else if file_type.is_symlink() {
-                    Ok(this.eval_libc("DT_LNK").to_u8()?.into())
-                } else {
+                match () {
+                    _ if file_type.is_dir() => Ok(this.eval_libc("DT_DIR").to_u8()?.into()),
+                    _ if file_type.is_file() => Ok(this.eval_libc("DT_REG").to_u8()?.into()),
+                    _ if file_type.is_symlink() => Ok(this.eval_libc("DT_LNK").to_u8()?.into()),
                     // Certain file types are only supported when the host is a Unix system.
-                    // (i.e. devices and sockets) If it is, check those cases, if not, fall back to
-                    // DT_UNKNOWN sooner.
-
                     #[cfg(unix)]
-                    {
-                        use std::os::unix::fs::FileTypeExt;
-                        if file_type.is_block_device() {
-                            Ok(this.eval_libc("DT_BLK").to_u8()?.into())
-                        } else if file_type.is_char_device() {
-                            Ok(this.eval_libc("DT_CHR").to_u8()?.into())
-                        } else if file_type.is_fifo() {
-                            Ok(this.eval_libc("DT_FIFO").to_u8()?.into())
-                        } else if file_type.is_socket() {
-                            Ok(this.eval_libc("DT_SOCK").to_u8()?.into())
-                        } else {
-                            Ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into())
-                        }
-                    }
-                    #[cfg(not(unix))]
-                    Ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into())
+                    _ if file_type.is_block_device() =>
+                        Ok(this.eval_libc("DT_BLK").to_u8()?.into()),
+                    #[cfg(unix)]
+                    _ if file_type.is_char_device() => Ok(this.eval_libc("DT_CHR").to_u8()?.into()),
+                    #[cfg(unix)]
+                    _ if file_type.is_fifo() => Ok(this.eval_libc("DT_FIFO").to_u8()?.into()),
+                    #[cfg(unix)]
+                    _ if file_type.is_socket() => Ok(this.eval_libc("DT_SOCK").to_u8()?.into()),
+                    // Fallback
+                    _ => Ok(this.eval_libc("DT_UNKNOWN").to_u8()?.into()),
                 }
             }
             Err(e) =>
@@ -387,7 +377,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`open`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
+            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
             return Ok(-1);
         }
 
@@ -443,7 +433,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`unlink`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
+            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
             return Ok(-1);
         }
 
@@ -474,7 +464,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`symlink`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
+            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
             return Ok(-1);
         }
 
@@ -775,7 +765,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`rename`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
+            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
             return Ok(-1);
         }
 
@@ -803,7 +793,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`mkdir`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
+            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
             return Ok(-1);
         }
 
@@ -831,7 +821,7 @@
         // Reject if isolation is enabled.
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`rmdir`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
+            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
             return Ok(-1);
         }
 
@@ -868,7 +858,7 @@
                 Ok(Scalar::from_target_usize(id, this))
             }
             Err(e) => {
-                this.set_last_error_from_io_error(e.kind())?;
+                this.set_last_error_from_io_error(e)?;
                 Ok(Scalar::null_ptr(this))
             }
         }
@@ -956,7 +946,7 @@
                 None
             }
             Some(Err(e)) => {
-                this.set_last_error_from_io_error(e.kind())?;
+                this.set_last_error_from_io_error(e)?;
                 None
             }
         };
@@ -1308,13 +1298,12 @@
                 Ok(path_bytes.len().try_into().unwrap())
             }
             Err(e) => {
-                this.set_last_error_from_io_error(e.kind())?;
+                this.set_last_error_from_io_error(e)?;
                 Ok(-1)
             }
         }
     }
 
-    #[cfg_attr(not(unix), allow(unused))]
     fn isatty(
         &mut self,
         miri_fd: &OpTy<'tcx, Provenance>,
@@ -1392,7 +1381,7 @@
                 Ok(Scalar::from_maybe_pointer(dest, this))
             }
             Err(e) => {
-                this.set_last_error_from_io_error(e.kind())?;
+                this.set_last_error_from_io_error(e)?;
                 Ok(Scalar::from_target_usize(0, this))
             }
         }
@@ -1467,8 +1456,8 @@
         #[cfg(unix)]
         {
             use std::os::unix::fs::OpenOptionsExt;
-            fopts.mode(0o600);
             // Do not allow others to read or modify this file.
+            fopts.mode(0o600);
             fopts.custom_flags(libc::O_EXCL);
         }
         #[cfg(windows)]
@@ -1513,7 +1502,7 @@
                         _ => {
                             // "On error, -1 is returned, and errno is set to
                             // indicate the error"
-                            this.set_last_error_from_io_error(e.kind())?;
+                            this.set_last_error_from_io_error(e)?;
                             return Ok(-1);
                         }
                     },
@@ -1592,7 +1581,7 @@
         let metadata = match metadata {
             Ok(metadata) => metadata,
             Err(e) => {
-                ecx.set_last_error_from_io_error(e.kind())?;
+                ecx.set_last_error_from_io_error(e)?;
                 return Ok(None);
             }
         };
diff --git a/src/tools/miri/src/shims/unix/linux/eventfd.rs b/src/tools/miri/src/shims/unix/linux/eventfd.rs
index a865f2e..f31c2bb 100644
--- a/src/tools/miri/src/shims/unix/linux/eventfd.rs
+++ b/src/tools/miri/src/shims/unix/linux/eventfd.rs
@@ -2,7 +2,6 @@
 //! Currently just a stub.
 use std::io;
 
-use rustc_middle::ty::TyCtxt;
 use rustc_target::abi::Endian;
 
 use crate::shims::unix::*;
@@ -52,11 +51,11 @@
         &mut self,
         _communicate_allowed: bool,
         bytes: &[u8],
-        tcx: TyCtxt<'tcx>,
+        ecx: &mut MiriInterpCx<'_, 'tcx>,
     ) -> InterpResult<'tcx, io::Result<usize>> {
         let bytes: [u8; 8] = bytes.try_into().unwrap(); // FIXME fail gracefully when this has the wrong size
         // Convert from target endianness to host endianness.
-        let num = match tcx.sess.target.endian {
+        let num = match ecx.tcx.sess.target.endian {
             Endian::Little => u64::from_le_bytes(bytes),
             Endian::Big => u64::from_be_bytes(bytes),
         };
diff --git a/src/tools/miri/src/shims/unix/linux/foreign_items.rs b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
index ecf82f2..b266610 100644
--- a/src/tools/miri/src/shims/unix/linux/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/linux/foreign_items.rs
@@ -117,6 +117,7 @@
                     // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)`
                     // is called if a `HashMap` is created the regular way (e.g. HashMap<K, V>).
                     id if id == sys_getrandom => {
+                        // Used by getrandom 0.1
                         // The first argument is the syscall id, so skip over it.
                         if args.len() < 4 {
                             throw_ub_format!(
@@ -124,7 +125,16 @@
                                 args.len()
                             );
                         }
-                        getrandom(this, &args[1], &args[2], &args[3], dest)?;
+
+                        let ptr = this.read_pointer(&args[1])?;
+                        let len = this.read_target_usize(&args[2])?;
+                        // The only supported flags are GRND_RANDOM and GRND_NONBLOCK,
+                        // neither of which have any effect on our current PRNG.
+                        // See <https://github.com/rust-lang/rust/pull/79196> for a discussion of argument sizes.
+                        let _flags = this.read_scalar(&args[3])?.to_i32();
+
+                        this.gen_random(ptr, len)?;
+                        this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
                     }
                     // `futex` is used by some synchronization primitives.
                     id if id == sys_futex => {
@@ -193,27 +203,6 @@
             _ => return Ok(EmulateItemResult::NotSupported),
         };
 
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
-
-// Shims the linux `getrandom` syscall.
-fn getrandom<'tcx>(
-    this: &mut MiriInterpCx<'_, 'tcx>,
-    ptr: &OpTy<'tcx, Provenance>,
-    len: &OpTy<'tcx, Provenance>,
-    flags: &OpTy<'tcx, Provenance>,
-    dest: &MPlaceTy<'tcx, Provenance>,
-) -> InterpResult<'tcx> {
-    let ptr = this.read_pointer(ptr)?;
-    let len = this.read_target_usize(len)?;
-
-    // The only supported flags are GRND_RANDOM and GRND_NONBLOCK,
-    // neither of which have any effect on our current PRNG.
-    // See <https://github.com/rust-lang/rust/pull/79196> for a discussion of argument sizes.
-    let _flags = this.read_scalar(flags)?.to_i32();
-
-    this.gen_random(ptr, len)?;
-    this.write_scalar(Scalar::from_target_usize(len, this), dest)?;
-    Ok(())
-}
diff --git a/src/tools/miri/src/shims/unix/macos/foreign_items.rs b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
index 912623b..2b9ce74 100644
--- a/src/tools/miri/src/shims/unix/macos/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/macos/foreign_items.rs
@@ -177,6 +177,6 @@
             _ => return Ok(EmulateItemResult::NotSupported),
         };
 
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs
index f52dc23..5f454e7 100644
--- a/src/tools/miri/src/shims/unix/mem.rs
+++ b/src/tools/miri/src/shims/unix/mem.rs
@@ -11,7 +11,7 @@
 //! calls to munmap, but for a very different reason. In principle, according to the man pages, it
 //! is possible to unmap arbitrary regions of address space. But in a high-level language like Rust
 //! this amounts to partial deallocation, which LLVM does not support. So any attempt to call our
-//! munmap shim which would partily unmap a region of address space previously mapped by mmap will
+//! munmap shim which would partially unmap a region of address space previously mapped by mmap will
 //! report UB.
 
 use crate::*;
@@ -42,9 +42,12 @@
         let map_shared = this.eval_libc_i32("MAP_SHARED");
         let map_fixed = this.eval_libc_i32("MAP_FIXED");
 
-        // This is a horrible hack, but on MacOS the guard page mechanism uses mmap
+        // This is a horrible hack, but on MacOS and Solaris the guard page mechanism uses mmap
         // in a way we do not support. We just give it the return value it expects.
-        if this.frame_in_std() && this.tcx.sess.target.os == "macos" && (flags & map_fixed) != 0 {
+        if this.frame_in_std()
+            && matches!(&*this.tcx.sess.target.os, "macos" | "solaris")
+            && (flags & map_fixed) != 0
+        {
             return Ok(Scalar::from_maybe_pointer(Pointer::from_addr_invalid(addr), this));
         }
 
@@ -75,7 +78,7 @@
         // * The implementation does not support the combination of accesses requested in the
         // prot argument.
         //
-        // Miri doesn't support MAP_FIXED or any any protections other than PROT_READ|PROT_WRITE.
+        // Miri doesn't support MAP_FIXED or any protections other than PROT_READ|PROT_WRITE.
         if flags & map_fixed != 0 || prot != prot_read | prot_write {
             this.set_last_error(this.eval_libc("ENOTSUP"))?;
             return Ok(this.eval_libc("MAP_FAILED"));
diff --git a/src/tools/miri/src/shims/unix/mod.rs b/src/tools/miri/src/shims/unix/mod.rs
index 6dee30d..dc9068f 100644
--- a/src/tools/miri/src/shims/unix/mod.rs
+++ b/src/tools/miri/src/shims/unix/mod.rs
@@ -8,6 +8,7 @@
 mod sync;
 mod thread;
 
+mod android;
 mod freebsd;
 mod linux;
 mod macos;
diff --git a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
index c01ae0e..6c51556 100644
--- a/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
+++ b/src/tools/miri/src/shims/unix/solarish/foreign_items.rs
@@ -2,7 +2,6 @@
 use rustc_target::spec::abi::Abi;
 
 use crate::*;
-use shims::EmulateItemResult;
 
 pub fn is_dyn_sym(_name: &str) -> bool {
     false
@@ -26,8 +25,26 @@
                 this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?;
             }
 
+            "stack_getbounds" => {
+                let [stack] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let stack = this.deref_pointer_as(stack, this.libc_ty_layout("stack_t"))?;
+
+                this.write_int_fields_named(
+                    &[
+                        ("ss_sp", this.machine.stack_addr.into()),
+                        ("ss_size", this.machine.stack_size.into()),
+                        // field set to 0 means not in an alternate signal stack
+                        // https://docs.oracle.com/cd/E86824_01/html/E54766/stack-getbounds-3c.html
+                        ("ss_flags", 0),
+                    ],
+                    &stack,
+                )?;
+
+                this.write_null(dest)?;
+            }
+
             _ => return Ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/unix/sync.rs b/src/tools/miri/src/shims/unix/sync.rs
index f24f279..0ba03d4 100644
--- a/src/tools/miri/src/shims/unix/sync.rs
+++ b/src/tools/miri/src/shims/unix/sync.rs
@@ -390,7 +390,7 @@
     Ok(())
 }
 
-/// After a thread waiting on a condvar was signalled:
+/// After a thread waiting on a condvar was signaled:
 /// Reacquire the conditional variable and remove the timeout callback if any
 /// was registered.
 fn post_cond_signal<'mir, 'tcx: 'mir>(
diff --git a/src/tools/miri/src/shims/wasi/foreign_items.rs b/src/tools/miri/src/shims/wasi/foreign_items.rs
new file mode 100644
index 0000000..774a5e7
--- /dev/null
+++ b/src/tools/miri/src/shims/wasi/foreign_items.rs
@@ -0,0 +1,40 @@
+use rustc_span::Symbol;
+use rustc_target::spec::abi::Abi;
+
+use crate::shims::alloc::EvalContextExt as _;
+use crate::*;
+
+pub fn is_dyn_sym(_name: &str) -> bool {
+    false
+}
+
+impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriInterpCx<'mir, 'tcx> {}
+pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
+    fn emulate_foreign_item_inner(
+        &mut self,
+        link_name: Symbol,
+        abi: Abi,
+        args: &[OpTy<'tcx, Provenance>],
+        dest: &MPlaceTy<'tcx, Provenance>,
+    ) -> InterpResult<'tcx, EmulateItemResult> {
+        let this = self.eval_context_mut();
+        match link_name.as_str() {
+            // Allocation
+            "posix_memalign" => {
+                let [memptr, align, size] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let result = this.posix_memalign(memptr, align, size)?;
+                this.write_scalar(result, dest)?;
+            }
+            "aligned_alloc" => {
+                let [align, size] =
+                    this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
+                let res = this.aligned_alloc(align, size)?;
+                this.write_pointer(res, dest)?;
+            }
+
+            _ => return Ok(EmulateItemResult::NotSupported),
+        }
+        Ok(EmulateItemResult::NeedsReturn)
+    }
+}
diff --git a/src/tools/miri/src/shims/wasi/mod.rs b/src/tools/miri/src/shims/wasi/mod.rs
new file mode 100644
index 0000000..09c6507
--- /dev/null
+++ b/src/tools/miri/src/shims/wasi/mod.rs
@@ -0,0 +1 @@
+pub mod foreign_items;
diff --git a/src/tools/miri/src/shims/windows/env.rs b/src/tools/miri/src/shims/windows/env.rs
index b3bc5d4..0e52959 100644
--- a/src/tools/miri/src/shims/windows/env.rs
+++ b/src/tools/miri/src/shims/windows/env.rs
@@ -153,7 +153,7 @@
 
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`GetCurrentDirectoryW`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
+            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
             return Ok(Scalar::from_u32(0));
         }
 
@@ -166,7 +166,7 @@
                     this.write_path_to_wide_str(&cwd, buf, size)?,
                 )));
             }
-            Err(e) => this.set_last_error_from_io_error(e.kind())?,
+            Err(e) => this.set_last_error_from_io_error(e)?,
         }
         Ok(Scalar::from_u32(0))
     }
@@ -185,7 +185,7 @@
 
         if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op {
             this.reject_in_isolation("`SetCurrentDirectoryW`", reject_with)?;
-            this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?;
+            this.set_last_error_from_io_error(ErrorKind::PermissionDenied.into())?;
 
             return Ok(this.eval_windows("c", "FALSE"));
         }
@@ -193,7 +193,7 @@
         match env::set_current_dir(path) {
             Ok(()) => Ok(this.eval_windows("c", "TRUE")),
             Err(e) => {
-                this.set_last_error_from_io_error(e.kind())?;
+                this.set_last_error_from_io_error(e)?;
                 Ok(this.eval_windows("c", "FALSE"))
             }
         }
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index dba5b7a..91def80 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -5,10 +5,9 @@
 use std::str;
 
 use rustc_span::Symbol;
-use rustc_target::abi::Size;
+use rustc_target::abi::{Align, Size};
 use rustc_target::spec::abi::Abi;
 
-use crate::shims::alloc::EvalContextExt as _;
 use crate::shims::os_str::bytes_to_os_str;
 use crate::shims::windows::*;
 use crate::*;
@@ -225,7 +224,7 @@
                 let filename = this.read_path_from_wide_str(filename)?;
                 let result = match win_absolute(&filename)? {
                     Err(err) => {
-                        this.set_last_error_from_io_error(err.kind())?;
+                        this.set_last_error_from_io_error(err)?;
                         Scalar::from_u32(0) // return zero upon failure
                     }
                     Ok(abs_filename) => {
@@ -248,8 +247,21 @@
                 let size = this.read_target_usize(size)?;
                 let heap_zero_memory = 0x00000008; // HEAP_ZERO_MEMORY
                 let zero_init = (flags & heap_zero_memory) == heap_zero_memory;
-                let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap)?;
-                this.write_pointer(res, dest)?;
+                // Alignment is twice the pointer size.
+                // Source: <https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc>
+                let align = this.tcx.pointer_size().bytes().strict_mul(2);
+                let ptr = this.allocate_ptr(
+                    Size::from_bytes(size),
+                    Align::from_bytes(align).unwrap(),
+                    MiriMemoryKind::WinHeap.into(),
+                )?;
+                if zero_init {
+                    this.write_bytes_ptr(
+                        ptr.into(),
+                        iter::repeat(0u8).take(usize::try_from(size).unwrap()),
+                    )?;
+                }
+                this.write_pointer(ptr, dest)?;
             }
             "HeapFree" => {
                 let [handle, flags, ptr] =
@@ -257,23 +269,41 @@
                 this.read_target_isize(handle)?;
                 this.read_scalar(flags)?.to_u32()?;
                 let ptr = this.read_pointer(ptr)?;
-                this.free(ptr, MiriMemoryKind::WinHeap)?;
+                // "This pointer can be NULL." It doesn't say what happens then, but presumably nothing.
+                // (https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapfree)
+                if !this.ptr_is_null(ptr)? {
+                    this.deallocate_ptr(ptr, None, MiriMemoryKind::WinHeap.into())?;
+                }
                 this.write_scalar(Scalar::from_i32(1), dest)?;
             }
             "HeapReAlloc" => {
-                let [handle, flags, ptr, size] =
+                let [handle, flags, old_ptr, size] =
                     this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
                 this.read_target_isize(handle)?;
                 this.read_scalar(flags)?.to_u32()?;
-                let ptr = this.read_pointer(ptr)?;
+                let old_ptr = this.read_pointer(old_ptr)?;
                 let size = this.read_target_usize(size)?;
-                let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?;
-                this.write_pointer(res, dest)?;
+                let align = this.tcx.pointer_size().bytes().strict_mul(2); // same as above
+                // The docs say that `old_ptr` must come from an earlier HeapAlloc or HeapReAlloc,
+                // so unlike C `realloc` we do *not* allow a NULL here.
+                // (https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heaprealloc)
+                let new_ptr = this.reallocate_ptr(
+                    old_ptr,
+                    None,
+                    Size::from_bytes(size),
+                    Align::from_bytes(align).unwrap(),
+                    MiriMemoryKind::WinHeap.into(),
+                )?;
+                this.write_pointer(new_ptr, dest)?;
             }
             "LocalFree" => {
                 let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
-                this.free(ptr, MiriMemoryKind::WinLocal)?;
+                // "If the hMem parameter is NULL, LocalFree ignores the parameter and returns NULL."
+                // (https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-localfree)
+                if !this.ptr_is_null(ptr)? {
+                    this.deallocate_ptr(ptr, None, MiriMemoryKind::WinLocal.into())?;
+                }
                 this.write_null(dest)?;
             }
 
@@ -513,6 +543,7 @@
                 throw_machine_stop!(TerminationInfo::Exit { code: code.into(), leak_check: false });
             }
             "SystemFunction036" => {
+                // used by getrandom 0.1
                 // This is really 'RtlGenRandom'.
                 let [ptr, len] =
                     this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
@@ -522,6 +553,7 @@
                 this.write_scalar(Scalar::from_bool(true), dest)?;
             }
             "ProcessPrng" => {
+                // used by `std`
                 let [ptr, len] =
                     this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
                 let ptr = this.read_pointer(ptr)?;
@@ -530,6 +562,7 @@
                 this.write_scalar(Scalar::from_i32(1), dest)?;
             }
             "BCryptGenRandom" => {
+                // used by getrandom 0.2
                 let [algorithm, ptr, len, flags] =
                     this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
                 let algorithm = this.read_scalar(algorithm)?;
@@ -729,6 +762,6 @@
             _ => return Ok(EmulateItemResult::NotSupported),
         }
 
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/aesni.rs b/src/tools/miri/src/shims/x86/aesni.rs
index 8dc3748..3a66c43 100644
--- a/src/tools/miri/src/shims/x86/aesni.rs
+++ b/src/tools/miri/src/shims/x86/aesni.rs
@@ -127,7 +127,7 @@
             // with an external crate.
             _ => return Ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
 
diff --git a/src/tools/miri/src/shims/x86/avx.rs b/src/tools/miri/src/shims/x86/avx.rs
index 86ef180..b1c61c8 100644
--- a/src/tools/miri/src/shims/x86/avx.rs
+++ b/src/tools/miri/src/shims/x86/avx.rs
@@ -344,6 +344,6 @@
             }
             _ => return Ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs
index 783be80..e0bd229 100644
--- a/src/tools/miri/src/shims/x86/avx2.rs
+++ b/src/tools/miri/src/shims/x86/avx2.rs
@@ -1,5 +1,5 @@
-use crate::rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::mir;
+use rustc_middle::ty::layout::LayoutOf as _;
 use rustc_middle::ty::Ty;
 use rustc_span::Symbol;
 use rustc_target::spec::abi::Abi;
@@ -81,7 +81,7 @@
 
                 let scale = this.read_scalar(scale)?.to_i8()?;
                 if !matches!(scale, 1 | 2 | 4 | 8) {
-                    throw_unsup_format!("invalid gather scale {scale}");
+                    panic!("invalid gather scale {scale}");
                 }
                 let scale = i64::from(scale);
 
@@ -440,6 +440,6 @@
             }
             _ => return Ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs
index e519fa5..48b7222 100644
--- a/src/tools/miri/src/shims/x86/mod.rs
+++ b/src/tools/miri/src/shims/x86/mod.rs
@@ -144,7 +144,7 @@
 
             _ => return Ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
 
@@ -200,7 +200,7 @@
     ) -> InterpResult<'tcx, Self> {
         // Only bits 0..=4 are used, remaining should be zero.
         if imm & !0b1_1111 != 0 {
-            throw_unsup_format!("invalid `imm` parameter of {intrinsic}: 0x{imm:x}");
+            panic!("invalid `imm` parameter of {intrinsic}: 0x{imm:x}");
         }
         // Bit 4 specifies whether the operation is quiet or signaling, which
         // we do not care in Miri.
@@ -683,7 +683,7 @@
         // SSE status register. Since we do not support modifying it from
         // Miri (or Rust), we assume it to be at its default mode (round-to-nearest).
         0b100..=0b111 => Ok(rustc_apfloat::Round::NearestTiesToEven),
-        rounding => throw_unsup_format!("unsupported rounding mode 0x{rounding:02x}"),
+        rounding => panic!("invalid rounding mode 0x{rounding:02x}"),
     }
 }
 
@@ -757,7 +757,7 @@
     Ok(())
 }
 
-/// Splits `op` (which must be a SIMD vector) into 128-bit chuncks.
+/// Splits `op` (which must be a SIMD vector) into 128-bit chunks.
 ///
 /// Returns a tuple where:
 /// * The first element is the number of 128-bit chunks (let's call it `N`).
@@ -788,7 +788,7 @@
     Ok((num_chunks, items_per_chunk, chunked_op))
 }
 
-/// Horizontaly performs `which` operation on adjacent values of
+/// Horizontally performs `which` operation on adjacent values of
 /// `left` and `right` SIMD vectors and stores the result in `dest`.
 /// "Horizontal" means that the i-th output element is calculated
 /// from the elements 2*i and 2*i+1 of the concatenation of `left` and
@@ -1256,7 +1256,7 @@
 
 /// Negates elements from `left` when the corresponding element in
 /// `right` is negative. If an element from `right` is zero, zero
-/// is writen to the corresponding output element.
+/// is written to the corresponding output element.
 /// In other words, multiplies `left` with `right.signum()`.
 fn psign<'tcx>(
     this: &mut crate::MiriInterpCx<'_, 'tcx>,
diff --git a/src/tools/miri/src/shims/x86/sse.rs b/src/tools/miri/src/shims/x86/sse.rs
index ea967a8..3636fb2 100644
--- a/src/tools/miri/src/shims/x86/sse.rs
+++ b/src/tools/miri/src/shims/x86/sse.rs
@@ -212,6 +212,6 @@
             }
             _ => return Ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/sse2.rs b/src/tools/miri/src/shims/x86/sse2.rs
index 31fa66a..54d1e0c 100644
--- a/src/tools/miri/src/shims/x86/sse2.rs
+++ b/src/tools/miri/src/shims/x86/sse2.rs
@@ -388,6 +388,6 @@
             }
             _ => return Ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/sse3.rs b/src/tools/miri/src/shims/x86/sse3.rs
index 8de339e..fa1dd07 100644
--- a/src/tools/miri/src/shims/x86/sse3.rs
+++ b/src/tools/miri/src/shims/x86/sse3.rs
@@ -51,6 +51,6 @@
             }
             _ => return Ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/sse41.rs b/src/tools/miri/src/shims/x86/sse41.rs
index 011a7a1..cd82108 100644
--- a/src/tools/miri/src/shims/x86/sse41.rs
+++ b/src/tools/miri/src/shims/x86/sse41.rs
@@ -176,6 +176,6 @@
             }
             _ => return Ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs
index d30de43..ec625da 100644
--- a/src/tools/miri/src/shims/x86/ssse3.rs
+++ b/src/tools/miri/src/shims/x86/ssse3.rs
@@ -137,6 +137,6 @@
             }
             _ => return Ok(EmulateItemResult::NotSupported),
         }
-        Ok(EmulateItemResult::NeedsJumping)
+        Ok(EmulateItemResult::NeedsReturn)
     }
 }
diff --git a/src/tools/miri/test-cargo-miri/run-test.py b/src/tools/miri/test-cargo-miri/run-test.py
index 2639d29..83f3e4c 100755
--- a/src/tools/miri/test-cargo-miri/run-test.py
+++ b/src/tools/miri/test-cargo-miri/run-test.py
@@ -10,6 +10,7 @@
 import re
 import subprocess
 import sys
+import argparse
 
 CGREEN  = '\33[32m'
 CBOLD   = '\33[1m'
@@ -25,8 +26,8 @@
     args = ["cargo", "miri", cmd] + CARGO_EXTRA_FLAGS
     if quiet:
         args += ["-q"]
-    if 'MIRI_TEST_TARGET' in os.environ:
-        args += ["--target", os.environ['MIRI_TEST_TARGET']]
+    if ARGS.target:
+        args += ["--target", ARGS.target]
     return args
 
 def normalize_stdout(str):
@@ -35,7 +36,7 @@
     return str
 
 def check_output(actual, path, name):
-    if os.environ.get("RUSTC_BLESS", "0") != "0":
+    if ARGS.bless:
         # Write the output only if bless is set
         open(path, mode='w').write(actual)
         return True
@@ -133,7 +134,7 @@
 
 def test_cargo_miri_test():
     # rustdoc is not run on foreign targets
-    is_foreign = 'MIRI_TEST_TARGET' in os.environ
+    is_foreign = ARGS.target is not None
     default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref"
     filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref"
 
@@ -182,16 +183,22 @@
         env={'MIRIFLAGS': "-Zmiri-permissive-provenance"},
     )
 
+args_parser = argparse.ArgumentParser(description='`cargo miri` testing')
+args_parser.add_argument('--target', help='the target to test')
+args_parser.add_argument('--bless', help='bless the reference files', action='store_true')
+ARGS = args_parser.parse_args()
+
 os.chdir(os.path.dirname(os.path.realpath(__file__)))
 os.environ["CARGO_TARGET_DIR"] = "target" # this affects the location of the target directory that we need to check
 os.environ["RUST_TEST_NOCAPTURE"] = "0" # this affects test output, so make sure it is not set
 os.environ["RUST_TEST_THREADS"] = "1" # avoid non-deterministic output due to concurrent test runs
 
-target_str = " for target {}".format(os.environ['MIRI_TEST_TARGET']) if 'MIRI_TEST_TARGET' in os.environ else ""
+target_str = " for target {}".format(ARGS.target) if ARGS.target else ""
 print(CGREEN + CBOLD + "## Running `cargo miri` tests{}".format(target_str) + CEND)
 
 test_cargo_miri_run()
 test_cargo_miri_test()
+
 # Ensure we did not create anything outside the expected target dir.
 for target_dir in ["target", "custom-run", "custom-test", "config-cli"]:
     if os.listdir(target_dir) != ["miri"]:
diff --git a/src/tools/miri/test_dependencies/Cargo.lock b/src/tools/miri/test_dependencies/Cargo.lock
index 3dd5eb9..c73d13a 100644
--- a/src/tools/miri/test_dependencies/Cargo.lock
+++ b/src/tools/miri/test_dependencies/Cargo.lock
@@ -18,12 +18,6 @@
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
 [[package]]
-name = "autocfg"
-version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
-
-[[package]]
 name = "backtrace"
 version = "0.3.71"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -51,12 +45,6 @@
 checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
 
 [[package]]
-name = "bytes"
-version = "1.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
-
-[[package]]
 name = "cc"
 version = "1.0.96"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -142,16 +130,6 @@
 checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
 
 [[package]]
-name = "lock_api"
-version = "0.4.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
-dependencies = [
- "autocfg",
- "scopeguard",
-]
-
-[[package]]
 name = "log"
 version = "0.4.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -192,7 +170,6 @@
  "libc",
  "num_cpus",
  "page_size",
- "rand",
  "tempfile",
  "tokio",
  "windows-sys 0.52.0",
@@ -234,41 +211,12 @@
 ]
 
 [[package]]
-name = "parking_lot"
-version = "0.12.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
-dependencies = [
- "lock_api",
- "parking_lot_core",
-]
-
-[[package]]
-name = "parking_lot_core"
-version = "0.9.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
-dependencies = [
- "cfg-if",
- "libc",
- "redox_syscall",
- "smallvec",
- "windows-targets 0.52.5",
-]
-
-[[package]]
 name = "pin-project-lite"
 version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
 
 [[package]]
-name = "ppv-lite86"
-version = "0.2.17"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
-
-[[package]]
 name = "proc-macro2"
 version = "1.0.81"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -287,45 +235,6 @@
 ]
 
 [[package]]
-name = "rand"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
-dependencies = [
- "libc",
- "rand_chacha",
- "rand_core",
-]
-
-[[package]]
-name = "rand_chacha"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
-dependencies = [
- "ppv-lite86",
- "rand_core",
-]
-
-[[package]]
-name = "rand_core"
-version = "0.6.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
-dependencies = [
- "getrandom 0.2.14",
-]
-
-[[package]]
-name = "redox_syscall"
-version = "0.5.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
-dependencies = [
- "bitflags",
-]
-
-[[package]]
 name = "rustc-demangle"
 version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -345,27 +254,6 @@
 ]
 
 [[package]]
-name = "scopeguard"
-version = "1.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
-
-[[package]]
-name = "signal-hook-registry"
-version = "1.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
-dependencies = [
- "libc",
-]
-
-[[package]]
-name = "smallvec"
-version = "1.13.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
-
-[[package]]
 name = "socket2"
 version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -405,13 +293,10 @@
 checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787"
 dependencies = [
  "backtrace",
- "bytes",
  "libc",
  "mio",
  "num_cpus",
- "parking_lot",
  "pin-project-lite",
- "signal-hook-registry",
  "socket2",
  "tokio-macros",
  "windows-sys 0.48.0",
diff --git a/src/tools/miri/test_dependencies/Cargo.toml b/src/tools/miri/test_dependencies/Cargo.toml
index 9f28e4d..e40dd50 100644
--- a/src/tools/miri/test_dependencies/Cargo.toml
+++ b/src/tools/miri/test_dependencies/Cargo.toml
@@ -11,15 +11,14 @@
 # all dependencies (and their transitive ones) listed here can be used in `tests/`.
 libc = "0.2"
 num_cpus = "1.10.1"
-tempfile = "3"
 
 getrandom_01 = { package = "getrandom", version = "0.1" }
 getrandom_02 = { package = "getrandom", version = "0.2", features = ["js"] }
-rand = { version = "0.8", features = ["small_rng"] }
 
 [target.'cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))'.dependencies]
+tempfile = "3"
 page_size = "0.6"
-tokio = { version = "1.24", features = ["full"] }
+tokio = { version = "1.24", features = ["macros", "rt-multi-thread", "time", "net"] }
 
 [target.'cfg(windows)'.dependencies]
 windows-sys = { version = "0.52", features = [ "Win32_Foundation", "Win32_System_Threading" ] }
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_cond_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs
similarity index 92%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_cond_double_destroy.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs
index 94ca349..f22f17b 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_cond_double_destroy.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 /// Test that destroying a pthread_cond twice fails, even without a check for number validity
 
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_cond_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_cond_double_destroy.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_cond_double_destroy.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_condattr_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs
similarity index 92%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_condattr_double_destroy.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs
index b5427d55..d0ccab4 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_condattr_double_destroy.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 //@ignore-target-apple: Our macOS condattr don't have any fields so we do not notice this.
 
 /// Test that destroying a pthread_condattr twice fails, even without a check for number validity
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_condattr_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_condattr_double_destroy.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_condattr_double_destroy.stderr
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.rs
index 7e6f490..9cd0a35 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_main_terminate.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 //@error-in-other-file: the main thread terminated without waiting for all remaining threads
 
 // Check that we terminate the program when the main thread terminates.
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs
index e1d3704..96dd99e 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_few_args.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 //! The thread function must have exactly one argument.
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs
index 7408634..d8fbc68 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_create_too_many_args.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 //! The thread function must have exactly one argument.
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.rs
index 0b810dc..e89d7a9 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_detached.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 // Joining a detached thread is undefined behavior.
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.rs
index 04ca4bb..cbad743 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_joined.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 // Joining an already joined thread is undefined behavior.
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.rs
index 7576518..002498e 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_main.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 // Joining the main thread is undefined behavior.
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs
index 966f416..f5b687a 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_multiple.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 // Joining the same thread from multiple threads is undefined behavior.
 
diff --git a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs
index 0c25c69..4bc1c82 100644
--- a/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_join_self.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 // We are making scheduler assumptions here.
 //@compile-flags: -Zmiri-preemption-rate=0
 
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_NULL_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs
similarity index 90%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_NULL_deadlock.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs
index 8b25107..0a494c5 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_NULL_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 //
 // Check that if we pass NULL attribute, then we get the default mutex type.
 
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_NULL_deadlock.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs
similarity index 92%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs
index 60d56d4..0328115 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 //@error-in-other-file: deadlock
 
 use std::cell::UnsafeCell;
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_deadlock.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_deadlock.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_default_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs
similarity index 91%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_default_deadlock.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs
index f443768..1038b89 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_default_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 //
 // Check that if we do not set the mutex type, it is the default.
 
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_default_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_default_deadlock.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_default_deadlock.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_destroy_locked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.rs
similarity index 91%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_destroy_locked.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.rs
index ec3965c..e474712 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_destroy_locked.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_destroy_locked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_destroy_locked.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_destroy_locked.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs
similarity index 92%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_double_destroy.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs
index 622c3ea..46f0c5f 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_double_destroy.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 /// Test that destroying a pthread_mutex twice fails, even without a check for number validity
 
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_double_destroy.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_double_destroy.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs
similarity index 92%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_deadlock.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs
index 5ea09fa..f311934 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_deadlock.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_deadlock.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.rs
similarity index 92%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.rs
index 8ce7542..2b5886d 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 fn main() {
     unsafe {
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_normal_unlock_unlocked.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_wrong_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs
similarity index 93%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_wrong_owner.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs
index b567752..686a394 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_wrong_owner.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 use std::cell::UnsafeCell;
 use std::sync::Arc;
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutex_wrong_owner.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutex_wrong_owner.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutexattr_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs
similarity index 91%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutexattr_double_destroy.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs
index 474a277..51f00d6 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutexattr_double_destroy.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 /// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity
 
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutexattr_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_mutexattr_double_destroy.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_mutexattr_double_destroy.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.rs
similarity index 83%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.rs
index 603580f..fa4575b 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 fn main() {
     let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_read_locked.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.rs
similarity index 83%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.rs
index ae44f22..e734a62 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 fn main() {
     let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_destroy_write_locked.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_double_destroy.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs
similarity index 88%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_double_destroy.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs
index 800986f..e96f7fc 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_double_destroy.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 /// Test that destroying a pthread_rwlock twice fails, even without a check for number validity
 
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_double_destroy.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_double_destroy.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_double_destroy.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs
similarity index 82%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs
index 782c95b..dffeee2 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 fn main() {
     let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs
similarity index 93%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs
index 1b498ad..328372b 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 use std::cell::UnsafeCell;
 use std::sync::Arc;
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_read_wrong_owner.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.rs
similarity index 78%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.rs
index 05f7e7a..ced6b7a 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 fn main() {
     let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_unlock_unlocked.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs
similarity index 93%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs
index 0f02c32..4174751 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 //@error-in-other-file: deadlock
 
 use std::cell::UnsafeCell;
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs
similarity index 82%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs
index 538f14e..099b8dc 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 fn main() {
     let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs
similarity index 93%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs
index 10be5b3..43b3ab0 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 //@error-in-other-file: deadlock
 
 use std::cell::UnsafeCell;
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs
similarity index 82%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs
index 2c963d3..2704ff1 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 fn main() {
     let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER);
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.rs
similarity index 93%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.rs
index dd09947..9a2cd09 100644
--- a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs
+++ b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 
 use std::cell::UnsafeCell;
 use std::sync::Arc;
diff --git a/src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr
rename to src/tools/miri/tests/fail-dep/concurrency/libc_pthread_rwlock_write_wrong_owner.stderr
diff --git a/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.rs b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.rs
new file mode 100644
index 0000000..9a33cdc
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.rs
@@ -0,0 +1,15 @@
+//@ignore-target-windows: Windows does not support the standard C11 aligned_alloc.
+
+fn main() {
+    // libc doesn't have this function (https://github.com/rust-lang/libc/issues/3689),
+    // so we declare it ourselves.
+    extern "C" {
+        fn aligned_alloc(alignment: libc::size_t, size: libc::size_t) -> *mut libc::c_void;
+    }
+
+    // Make sure even zero-sized allocations need to be freed.
+
+    unsafe {
+        aligned_alloc(2, 0); //~ERROR: memory leaked
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr
new file mode 100644
index 0000000..b0756d5
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/aligned_alloc_size_zero_leak.stderr
@@ -0,0 +1,15 @@
+error: memory leaked: ALLOC (C heap, size: 0, align: 2), allocated here:
+  --> $DIR/aligned_alloc_size_zero_leak.rs:LL:CC
+   |
+LL |         aligned_alloc(2, 0);
+   |         ^^^^^^^^^^^^^^^^^^^
+   |
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/aligned_alloc_size_zero_leak.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.rs b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs
similarity index 89%
rename from src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.rs
rename to src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs
index 2b9e7a3..a1895fe 100644
--- a/src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.rs
+++ b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.rs
@@ -1,5 +1,5 @@
 //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No libc env support on Windows
 
 use std::env;
 use std::thread;
diff --git a/src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.stderr b/src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/env-set_var-data-race.stderr
rename to src/tools/miri/tests/fail-dep/libc/env-set_var-data-race.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/fs/close_stdout.rs b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs
similarity index 82%
rename from src/tools/miri/tests/fail-dep/shims/fs/close_stdout.rs
rename to src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs
index 09da850..42b7e2b 100644
--- a/src/tools/miri/tests/fail-dep/shims/fs/close_stdout.rs
+++ b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No libc IO on Windows
 //@compile-flags: -Zmiri-disable-isolation
 
 // FIXME: standard handles cannot be closed (https://github.com/rust-lang/rust/issues/40032)
diff --git a/src/tools/miri/tests/fail-dep/shims/fs/close_stdout.stderr b/src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/fs/close_stdout.stderr
rename to src/tools/miri/tests/fail-dep/libc/fs/close_stdout.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/fs/isolated_stdin.rs b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs
similarity index 83%
rename from src/tools/miri/tests/fail-dep/shims/fs/isolated_stdin.rs
rename to src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs
index a45f805..3c62015 100644
--- a/src/tools/miri/tests/fail-dep/shims/fs/isolated_stdin.rs
+++ b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No libc IO on Windows
 
 fn main() -> std::io::Result<()> {
     let mut bytes = [0u8; 512];
diff --git a/src/tools/miri/tests/fail-dep/shims/fs/isolated_stdin.stderr b/src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/fs/isolated_stdin.stderr
rename to src/tools/miri/tests/fail-dep/libc/fs/isolated_stdin.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/fs/mkstemp_immutable_arg.rs b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs
similarity index 86%
rename from src/tools/miri/tests/fail-dep/shims/fs/mkstemp_immutable_arg.rs
rename to src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs
index ba9f404..6d951a3 100644
--- a/src/tools/miri/tests/fail-dep/shims/fs/mkstemp_immutable_arg.rs
+++ b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No mkstemp on Windows
 //@compile-flags: -Zmiri-disable-isolation
 
 fn main() {
diff --git a/src/tools/miri/tests/fail-dep/shims/fs/mkstemp_immutable_arg.stderr b/src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/fs/mkstemp_immutable_arg.stderr
rename to src/tools/miri/tests/fail-dep/libc/fs/mkstemp_immutable_arg.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/fs/read_from_stdout.rs b/src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.rs
similarity index 83%
rename from src/tools/miri/tests/fail-dep/shims/fs/read_from_stdout.rs
rename to src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.rs
index 073fca4..624f584 100644
--- a/src/tools/miri/tests/fail-dep/shims/fs/read_from_stdout.rs
+++ b/src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.rs
@@ -1,5 +1,5 @@
 //@compile-flags: -Zmiri-disable-isolation
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No libc IO on Windows
 
 fn main() -> std::io::Result<()> {
     let mut bytes = [0u8; 512];
diff --git a/src/tools/miri/tests/fail-dep/shims/fs/read_from_stdout.stderr b/src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/fs/read_from_stdout.stderr
rename to src/tools/miri/tests/fail-dep/libc/fs/read_from_stdout.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/fs/unix_open_missing_required_mode.rs b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs
similarity index 89%
rename from src/tools/miri/tests/fail-dep/shims/fs/unix_open_missing_required_mode.rs
rename to src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs
index ae231d4..d783967 100644
--- a/src/tools/miri/tests/fail-dep/shims/fs/unix_open_missing_required_mode.rs
+++ b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No libc IO on Windows
 //@compile-flags: -Zmiri-disable-isolation
 
 fn main() {
diff --git a/src/tools/miri/tests/fail-dep/shims/fs/unix_open_missing_required_mode.stderr b/src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/fs/unix_open_missing_required_mode.stderr
rename to src/tools/miri/tests/fail-dep/libc/fs/unix_open_missing_required_mode.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.rs b/src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.rs
similarity index 79%
rename from src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.rs
rename to src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.rs
index d039ad7..683c55e 100644
--- a/src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.rs
+++ b/src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No libc IO on Windows
 
 fn main() -> std::io::Result<()> {
     let bytes = b"hello";
diff --git a/src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.stderr b/src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/fs/write_to_stdin.stderr
rename to src/tools/miri/tests/fail-dep/libc/fs/write_to_stdin.stderr
diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.rs b/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.rs
new file mode 100644
index 0000000..3298d61
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.rs
@@ -0,0 +1,7 @@
+fn main() {
+    unsafe {
+        let ptr = libc::malloc(0);
+        libc::free(ptr);
+        libc::free(ptr); //~ERROR: dangling
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.stderr b/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.stderr
new file mode 100644
index 0000000..6437c9d
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_double_free.stderr
@@ -0,0 +1,25 @@
+error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
+  --> $DIR/malloc_zero_double_free.rs:LL:CC
+   |
+LL |         libc::free(ptr);
+   |         ^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+help: ALLOC was allocated here:
+  --> $DIR/malloc_zero_double_free.rs:LL:CC
+   |
+LL |         let ptr = libc::malloc(0);
+   |                   ^^^^^^^^^^^^^^^
+help: ALLOC was deallocated here:
+  --> $DIR/malloc_zero_double_free.rs:LL:CC
+   |
+LL |         libc::free(ptr);
+   |         ^^^^^^^^^^^^^^^
+   = note: BACKTRACE (of the first span):
+   = note: inside `main` at $DIR/malloc_zero_double_free.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.rs b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.rs
new file mode 100644
index 0000000..b09a74f
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.rs
@@ -0,0 +1,5 @@
+fn main() {
+    unsafe {
+        let _ptr = libc::malloc(0); //~ERROR: memory leak
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr
new file mode 100644
index 0000000..65ce0dc
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/malloc_zero_memory_leak.stderr
@@ -0,0 +1,15 @@
+error: memory leaked: ALLOC (C heap, size: 0, align: 1), allocated here:
+  --> $DIR/malloc_zero_memory_leak.rs:LL:CC
+   |
+LL |         let _ptr = libc::malloc(0);
+   |                    ^^^^^^^^^^^^^^^
+   |
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/malloc_zero_memory_leak.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail-dep/shims/memchr_null.rs b/src/tools/miri/tests/fail-dep/libc/memchr_null.rs
similarity index 77%
rename from src/tools/miri/tests/fail-dep/shims/memchr_null.rs
rename to src/tools/miri/tests/fail-dep/libc/memchr_null.rs
index 6bc7af7..672cc10 100644
--- a/src/tools/miri/tests/fail-dep/shims/memchr_null.rs
+++ b/src/tools/miri/tests/fail-dep/libc/memchr_null.rs
@@ -1,5 +1,3 @@
-//@ignore-target-windows: No libc on Windows
-
 use std::ptr;
 
 // null is explicitly called out as UB in the C docs.
diff --git a/src/tools/miri/tests/fail-dep/shims/memchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memchr_null.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/memchr_null.stderr
rename to src/tools/miri/tests/fail-dep/libc/memchr_null.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/memcmp_null.rs b/src/tools/miri/tests/fail-dep/libc/memcmp_null.rs
similarity index 78%
rename from src/tools/miri/tests/fail-dep/shims/memcmp_null.rs
rename to src/tools/miri/tests/fail-dep/libc/memcmp_null.rs
index a4e0034..066af4a 100644
--- a/src/tools/miri/tests/fail-dep/shims/memcmp_null.rs
+++ b/src/tools/miri/tests/fail-dep/libc/memcmp_null.rs
@@ -1,5 +1,3 @@
-//@ignore-target-windows: No libc on Windows
-
 use std::ptr;
 
 // null is explicitly called out as UB in the C docs.
diff --git a/src/tools/miri/tests/fail-dep/shims/memcmp_null.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/memcmp_null.stderr
rename to src/tools/miri/tests/fail-dep/libc/memcmp_null.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/memcmp_zero.rs b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.rs
similarity index 90%
rename from src/tools/miri/tests/fail-dep/shims/memcmp_zero.rs
rename to src/tools/miri/tests/fail-dep/libc/memcmp_zero.rs
index f2ddc20..e28aa26 100644
--- a/src/tools/miri/tests/fail-dep/shims/memcmp_zero.rs
+++ b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.rs
@@ -1,4 +1,3 @@
-//@ignore-target-windows: No libc on Windows
 //@compile-flags: -Zmiri-permissive-provenance
 
 // C says that passing "invalid" pointers is UB for all string functions.
diff --git a/src/tools/miri/tests/fail-dep/shims/memcmp_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/memcmp_zero.stderr
rename to src/tools/miri/tests/fail-dep/libc/memcmp_zero.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/memcpy_zero.rs b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.rs
similarity index 88%
rename from src/tools/miri/tests/fail-dep/shims/memcpy_zero.rs
rename to src/tools/miri/tests/fail-dep/libc/memcpy_zero.rs
index 5283fea..b37ed7d 100644
--- a/src/tools/miri/tests/fail-dep/shims/memcpy_zero.rs
+++ b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.rs
@@ -1,4 +1,3 @@
-//@ignore-target-windows: No libc on Windows
 //@compile-flags: -Zmiri-permissive-provenance
 // C's memcpy is 0 bytes is UB for some pointers that are allowed in Rust's `copy_nonoverlapping`.
 
diff --git a/src/tools/miri/tests/fail-dep/shims/memcpy_zero.stderr b/src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/memcpy_zero.stderr
rename to src/tools/miri/tests/fail-dep/libc/memcpy_zero.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/memrchr_null.rs b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs
similarity index 81%
rename from src/tools/miri/tests/fail-dep/shims/memrchr_null.rs
rename to src/tools/miri/tests/fail-dep/libc/memrchr_null.rs
index b6707d5..f06336b 100644
--- a/src/tools/miri/tests/fail-dep/shims/memrchr_null.rs
+++ b/src/tools/miri/tests/fail-dep/libc/memrchr_null.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No `memrchr` on Windows
 //@ignore-target-apple: No `memrchr` on some apple targets
 
 use std::ptr;
diff --git a/src/tools/miri/tests/fail-dep/shims/memrchr_null.stderr b/src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/memrchr_null.stderr
rename to src/tools/miri/tests/fail-dep/libc/memrchr_null.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/mmap_invalid_dealloc.rs b/src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.rs
similarity index 90%
rename from src/tools/miri/tests/fail-dep/shims/mmap_invalid_dealloc.rs
rename to src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.rs
index 70f7a6a..9d55a49 100644
--- a/src/tools/miri/tests/fail-dep/shims/mmap_invalid_dealloc.rs
+++ b/src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.rs
@@ -1,5 +1,5 @@
 //@compile-flags: -Zmiri-disable-isolation
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No mmap on Windows
 
 #![feature(rustc_private)]
 
diff --git a/src/tools/miri/tests/fail-dep/shims/mmap_invalid_dealloc.stderr b/src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/mmap_invalid_dealloc.stderr
rename to src/tools/miri/tests/fail-dep/libc/mmap_invalid_dealloc.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/mmap_use_after_munmap.rs b/src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.rs
similarity index 90%
rename from src/tools/miri/tests/fail-dep/shims/mmap_use_after_munmap.rs
rename to src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.rs
index c97b013..05ac232 100644
--- a/src/tools/miri/tests/fail-dep/shims/mmap_use_after_munmap.rs
+++ b/src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.rs
@@ -1,5 +1,5 @@
 //@compile-flags: -Zmiri-disable-isolation
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No mmap on Windows
 
 #![feature(rustc_private)]
 
diff --git a/src/tools/miri/tests/fail-dep/shims/mmap_use_after_munmap.stderr b/src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/mmap_use_after_munmap.stderr
rename to src/tools/miri/tests/fail-dep/libc/mmap_use_after_munmap.stderr
diff --git a/src/tools/miri/tests/fail-dep/shims/munmap_partial.rs b/src/tools/miri/tests/fail-dep/libc/munmap_partial.rs
similarity index 93%
rename from src/tools/miri/tests/fail-dep/shims/munmap_partial.rs
rename to src/tools/miri/tests/fail-dep/libc/munmap_partial.rs
index d7aef47..4386dc7 100644
--- a/src/tools/miri/tests/fail-dep/shims/munmap_partial.rs
+++ b/src/tools/miri/tests/fail-dep/libc/munmap_partial.rs
@@ -1,7 +1,7 @@
 //! The man pages for mmap/munmap suggest that it is possible to partly unmap a previously-mapped
 //! region of address space, but to LLVM that would be partial deallocation, which LLVM does not
 //! support. So even though the man pages say this sort of use is possible, we must report UB.
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No mmap on Windows
 //@normalize-stderr-test: "size [0-9]+ and alignment" -> "size SIZE and alignment"
 
 fn main() {
diff --git a/src/tools/miri/tests/fail-dep/shims/munmap_partial.stderr b/src/tools/miri/tests/fail-dep/libc/munmap_partial.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/shims/munmap_partial.stderr
rename to src/tools/miri/tests/fail-dep/libc/munmap_partial.stderr
diff --git a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_double_free.rs b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_double_free.rs
new file mode 100644
index 0000000..b6b7b00
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_double_free.rs
@@ -0,0 +1,14 @@
+//@ignore-target-windows: No posix_memalign on Windows
+
+use std::ptr;
+
+fn main() {
+    let mut ptr: *mut libc::c_void = ptr::null_mut();
+    let align = 64;
+    let size = 0;
+    unsafe {
+        let _ = libc::posix_memalign(&mut ptr, align, size);
+        libc::free(ptr);
+        libc::free(ptr); //~ERROR: dangling
+    }
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_double_free.stderr b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_double_free.stderr
new file mode 100644
index 0000000..3ed117c
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_double_free.stderr
@@ -0,0 +1,25 @@
+error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
+  --> $DIR/posix_memalign_size_zero_double_free.rs:LL:CC
+   |
+LL |         libc::free(ptr);
+   |         ^^^^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+help: ALLOC was allocated here:
+  --> $DIR/posix_memalign_size_zero_double_free.rs:LL:CC
+   |
+LL |         let _ = libc::posix_memalign(&mut ptr, align, size);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: ALLOC was deallocated here:
+  --> $DIR/posix_memalign_size_zero_double_free.rs:LL:CC
+   |
+LL |         libc::free(ptr);
+   |         ^^^^^^^^^^^^^^^
+   = note: BACKTRACE (of the first span):
+   = note: inside `main` at $DIR/posix_memalign_size_zero_double_free.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.rs b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.rs
new file mode 100644
index 0000000..1a4c960
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.rs
@@ -0,0 +1,10 @@
+//@ignore-target-windows: No posix_memalign on Windows
+
+use std::ptr;
+
+fn main() {
+    let mut ptr: *mut libc::c_void = ptr::null_mut();
+    let align = 64;
+    let size = 0;
+    let _ = unsafe { libc::posix_memalign(&mut ptr, align, size) }; //~ERROR: memory leak
+}
diff --git a/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr
new file mode 100644
index 0000000..7ea0fa3
--- /dev/null
+++ b/src/tools/miri/tests/fail-dep/libc/posix_memalign_size_zero_leak.stderr
@@ -0,0 +1,15 @@
+error: memory leaked: ALLOC (C heap, size: 0, align: 64), allocated here:
+  --> $DIR/posix_memalign_size_zero_leak.rs:LL:CC
+   |
+LL |     let _ = unsafe { libc::posix_memalign(&mut ptr, align, size) };
+   |                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/posix_memalign_size_zero_leak.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+note: the evaluated program leaked memory, pass `-Zmiri-ignore-leaks` to disable this check
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail-dep/realloc-zero.rs b/src/tools/miri/tests/fail-dep/libc/realloc-zero.rs
similarity index 81%
rename from src/tools/miri/tests/fail-dep/realloc-zero.rs
rename to src/tools/miri/tests/fail-dep/libc/realloc-zero.rs
index 1482798..0e210f3 100644
--- a/src/tools/miri/tests/fail-dep/realloc-zero.rs
+++ b/src/tools/miri/tests/fail-dep/libc/realloc-zero.rs
@@ -1,5 +1,3 @@
-//@ignore-target-windows: No libc on Windows
-
 fn main() {
     unsafe {
         let p1 = libc::malloc(20);
diff --git a/src/tools/miri/tests/fail-dep/realloc-zero.stderr b/src/tools/miri/tests/fail-dep/libc/realloc-zero.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/realloc-zero.stderr
rename to src/tools/miri/tests/fail-dep/libc/realloc-zero.stderr
diff --git a/src/tools/miri/tests/fail-dep/unsupported_incomplete_function.rs b/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.rs
similarity index 87%
rename from src/tools/miri/tests/fail-dep/unsupported_incomplete_function.rs
rename to src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.rs
index 6ef842c..cd8422f 100644
--- a/src/tools/miri/tests/fail-dep/unsupported_incomplete_function.rs
+++ b/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.rs
@@ -1,6 +1,6 @@
 //! `signal()` is special on Linux and macOS that it's only supported within libstd.
 //! The implementation is not complete enough to permit user code to call it.
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No `libc::signal` on Windows
 //@normalize-stderr-test: "OS `.*`" -> "$$OS"
 
 fn main() {
diff --git a/src/tools/miri/tests/fail-dep/unsupported_incomplete_function.stderr b/src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.stderr
similarity index 100%
rename from src/tools/miri/tests/fail-dep/unsupported_incomplete_function.stderr
rename to src/tools/miri/tests/fail-dep/libc/unsupported_incomplete_function.stderr
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.rs b/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.rs
deleted file mode 100644
index a1fefe0..0000000
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Make sure we find these even with many checks disabled.
-//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation
-
-fn main() {
-    let p = {
-        let b = Box::new(42);
-        &*b as *const i32 as *const ()
-    };
-    let _x = unsafe { *p }; //~ ERROR: has been freed
-}
diff --git a/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.stderr b/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.stderr
deleted file mode 100644
index 72b9a4a..0000000
--- a/src/tools/miri/tests/fail/dangling_pointers/dangling_zst_deref.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
-  --> $DIR/dangling_zst_deref.rs:LL:CC
-   |
-LL |     let _x = unsafe { *p };
-   |                       ^^ memory access failed: ALLOC has been freed, so this pointer is dangling
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-help: ALLOC was allocated here:
-  --> $DIR/dangling_zst_deref.rs:LL:CC
-   |
-LL |         let b = Box::new(42);
-   |                 ^^^^^^^^^^^^
-help: ALLOC was deallocated here:
-  --> $DIR/dangling_zst_deref.rs:LL:CC
-   |
-LL |     };
-   |     ^
-   = note: BACKTRACE (of the first span):
-   = note: inside `main` at $DIR/dangling_zst_deref.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs b/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs
deleted file mode 100644
index 73d0b12..0000000
--- a/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-fn main() {
-    // This pointer *could* be NULL so we cannot load from it, not even at ZST
-    let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *const ();
-    let _x: () = unsafe { *ptr }; //~ ERROR: out-of-bounds
-}
diff --git a/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr b/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr
deleted file mode 100644
index 13c53e2..0000000
--- a/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: Undefined Behavior: memory access failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds
-  --> $DIR/maybe_null_pointer_deref_zst.rs:LL:CC
-   |
-LL |     let _x: () = unsafe { *ptr };
-   |                           ^^^^ memory access failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE:
-   = note: inside `main` at $DIR/maybe_null_pointer_deref_zst.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs
deleted file mode 100644
index 5537207..0000000
--- a/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-fn main() {
-    // This pointer *could* be NULL so we cannot load from it, not even at ZST.
-    // Not using the () type here, as writes of that type do not even have MIR generated.
-    // Also not assigning directly as that's array initialization, not assignment.
-    let zst_val = [1u8; 0];
-    let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *mut [u8; 0];
-    unsafe { *ptr = zst_val }; //~ ERROR: out-of-bounds
-}
diff --git a/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr b/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr
deleted file mode 100644
index e4e23e8..0000000
--- a/src/tools/miri/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: Undefined Behavior: memory access failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds
-  --> $DIR/maybe_null_pointer_write_zst.rs:LL:CC
-   |
-LL |     unsafe { *ptr = zst_val };
-   |              ^^^^^^^^^^^^^^ memory access failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE:
-   = note: inside `main` at $DIR/maybe_null_pointer_write_zst.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref_zst.rs b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref_zst.rs
deleted file mode 100644
index f8af43f..0000000
--- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref_zst.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-#[allow(deref_nullptr)]
-fn main() {
-    let x: () = unsafe { *std::ptr::null() }; //~ ERROR: memory access failed: null pointer is a dangling pointer
-    panic!("this should never print: {:?}", x);
-}
diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr
deleted file mode 100644
index 1a8794f..0000000
--- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
-  --> $DIR/null_pointer_deref_zst.rs:LL:CC
-   |
-LL |     let x: () = unsafe { *std::ptr::null() };
-   |                          ^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE:
-   = note: inside `main` at $DIR/null_pointer_deref_zst.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write_zst.rs b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write_zst.rs
deleted file mode 100644
index edd6c8f..0000000
--- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write_zst.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-#[allow(deref_nullptr)]
-fn main() {
-    // Not using the () type here, as writes of that type do not even have MIR generated.
-    // Also not assigning directly as that's array initialization, not assignment.
-    let zst_val = [1u8; 0];
-    unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) };
-    //~^ERROR: memory access failed: null pointer is a dangling pointer
-}
diff --git a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write_zst.stderr b/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write_zst.stderr
deleted file mode 100644
index 1d4704e..0000000
--- a/src/tools/miri/tests/fail/dangling_pointers/null_pointer_write_zst.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
-  --> $DIR/null_pointer_write_zst.rs:LL:CC
-   |
-LL |     unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE:
-   = note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.rs b/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.rs
index 428f371..eca6d90 100644
--- a/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.rs
+++ b/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.rs
@@ -2,7 +2,7 @@
 #![feature(custom_mir)]
 
 use std::intrinsics::mir::*;
-use std::num::NonZeroI32;
+use std::num::NonZero;
 
 // We define our own option type so that we can control the variant indices.
 #[allow(unused)]
@@ -13,7 +13,7 @@
 use Option::*;
 
 #[custom_mir(dialect = "runtime", phase = "optimized")]
-fn set_discriminant(ptr: &mut Option<NonZeroI32>) {
+fn set_discriminant(ptr: &mut Option<NonZero<i32>>) {
     mir! {
         {
             // We set the discriminant to `Some`, which is a NOP since this is the niched variant.
diff --git a/src/tools/miri/tests/fail/environ-gets-deallocated.rs b/src/tools/miri/tests/fail/environ-gets-deallocated.rs
index 6dcf1fdb..5391a91 100644
--- a/src/tools/miri/tests/fail/environ-gets-deallocated.rs
+++ b/src/tools/miri/tests/fail/environ-gets-deallocated.rs
@@ -1,6 +1,5 @@
 //@ignore-target-windows: Windows does not have a global environ list that the program can access directly
 
-#[cfg(any(target_os = "linux", target_os = "freebsd"))]
 fn get_environ() -> *const *const u8 {
     extern "C" {
         static mut environ: *const *const u8;
@@ -8,14 +7,6 @@
     unsafe { environ }
 }
 
-#[cfg(target_os = "macos")]
-fn get_environ() -> *const *const u8 {
-    extern "C" {
-        fn _NSGetEnviron() -> *mut *const *const u8;
-    }
-    unsafe { *_NSGetEnviron() }
-}
-
 fn main() {
     let pointer = get_environ();
     let _x = unsafe { *pointer };
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs
index 2cf4e04..c590048 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.rs
@@ -1,7 +1,7 @@
-use std::num::*;
+use std::num::NonZero;
 
 #[repr(C)]
-struct S1(NonZeroI32);
+struct S1(NonZero<i32>);
 
 #[repr(C)]
 struct S2(i32);
@@ -11,6 +11,6 @@
 fn main() {
     let fnptr: fn(S2) = callee;
     let fnptr: fn(S1) = unsafe { std::mem::transmute(fnptr) };
-    fnptr(S1(NonZeroI32::new(1).unwrap()));
+    fnptr(S1(NonZero::new(1).unwrap()));
     //~^ ERROR: calling a function with argument of type S2 passing data of type S1
 }
diff --git a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr
index eaacc32..8ec19db 100644
--- a/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr
+++ b/src/tools/miri/tests/fail/function_pointers/abi_mismatch_repr_C.stderr
@@ -1,8 +1,8 @@
 error: Undefined Behavior: calling a function with argument of type S2 passing data of type S1
   --> $DIR/abi_mismatch_repr_C.rs:LL:CC
    |
-LL |     fnptr(S1(NonZeroI32::new(1).unwrap()));
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with argument of type S2 passing data of type S1
+LL |     fnptr(S1(NonZero::new(1).unwrap()));
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with argument of type S2 passing data of type S1
    |
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_null.rs b/src/tools/miri/tests/fail/intrinsics/copy_null.rs
deleted file mode 100644
index 237e517..0000000
--- a/src/tools/miri/tests/fail/intrinsics/copy_null.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-#![feature(intrinsics)]
-
-// Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: usize);
-}
-
-fn main() {
-    let mut data = [0u16; 4];
-    let ptr = &mut data[0] as *mut u16;
-    // Even copying 0 elements from NULL should error.
-    unsafe {
-        copy_nonoverlapping(std::ptr::null(), ptr, 0); //~ ERROR: memory access failed: null pointer is a dangling pointer
-    }
-}
diff --git a/src/tools/miri/tests/fail/intrinsics/copy_null.stderr b/src/tools/miri/tests/fail/intrinsics/copy_null.stderr
deleted file mode 100644
index d73c034..0000000
--- a/src/tools/miri/tests/fail/intrinsics/copy_null.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
-  --> $DIR/copy_null.rs:LL:CC
-   |
-LL |         copy_nonoverlapping(std::ptr::null(), ptr, 0);
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE:
-   = note: inside `main` at $DIR/copy_null.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_0_plus_0.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_0_plus_0.rs
deleted file mode 100644
index e2329c1..0000000
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_0_plus_0.rs
+++ /dev/null
@@ -1,9 +0,0 @@
-//@compile-flags: -Zmiri-permissive-provenance
-
-#[rustfmt::skip] // fails with "left behind trailing whitespace"
-fn main() {
-    let x = 0 as *mut i32;
-    let _x = x.wrapping_offset(8); // ok, this has no inbounds tag
-    let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never inbounds
-    //~^ERROR: null pointer is a dangling pointer
-}
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr
deleted file mode 100644
index a8984c7..0000000
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance)
-  --> $DIR/ptr_offset_0_plus_0.rs:LL:CC
-   |
-LL |     let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never inbounds
-   |                       ^^^^^^^^^^^ out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance)
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE:
-   = note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs
new file mode 100644
index 0000000..57b4fd0
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.rs
@@ -0,0 +1,21 @@
+#![feature(strict_provenance)]
+use core::ptr;
+
+fn main() {
+    unsafe {
+        let base = ptr::without_provenance::<()>(10);
+        let unit = &*base;
+        let p1 = unit as *const ();
+
+        let base = ptr::without_provenance::<()>(11);
+        let unit = &*base;
+        let p2 = unit as *const ();
+
+        // Seems to work because they are same pointer
+        // even though it's dangling.
+        let _ = p1.byte_offset_from(p1);
+
+        // UB because different pointers.
+        let _ = p1.byte_offset_from(p2); //~ERROR: different pointers without provenance
+    }
+}
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr
new file mode 100644
index 0000000..6e9e563
--- /dev/null
+++ b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_different_ints.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
+  --> $DIR/ptr_offset_from_different_ints.rs:LL:CC
+   |
+LL |         let _ = p1.byte_offset_from(p2);
+   |                 ^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/ptr_offset_from_different_ints.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs
deleted file mode 100644
index 0e5acf0..0000000
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-fn main() {
-    let start_ptr = &4 as *const _ as *const u8;
-    let length = 10;
-    let end_ptr = start_ptr.wrapping_add(length);
-    // Even if the offset is 0, a dangling OOB pointer is not allowed.
-    unsafe { end_ptr.offset_from(end_ptr) }; //~ERROR: pointer at offset 10 is out-of-bounds
-}
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr
deleted file mode 100644
index 32a4461..0000000
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_from_oob.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: Undefined Behavior: out-of-bounds `offset_from`: ALLOC has size 4, so pointer at offset 10 is out-of-bounds
-  --> $DIR/ptr_offset_from_oob.rs:LL:CC
-   |
-LL |     unsafe { end_ptr.offset_from(end_ptr) };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC has size 4, so pointer at offset 10 is out-of-bounds
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE:
-   = note: inside `main` at $DIR/ptr_offset_from_oob.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs b/src/tools/miri/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs
deleted file mode 100644
index 575e288..0000000
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-#[rustfmt::skip] // fails with "left behind trailing whitespace"
-fn main() {
-    let x = Box::into_raw(Box::new(0u32));
-    let x = x.wrapping_offset(8); // ok, this has no inbounds tag
-    let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is not inbounds of the only object it can point to
-    //~^ERROR: pointer at offset 32 is out-of-bounds
-}
diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr
deleted file mode 100644
index 304d362..0000000
--- a/src/tools/miri/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer at offset 32 is out-of-bounds
-  --> $DIR/ptr_offset_ptr_plus_0.rs:LL:CC
-   |
-LL |     let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is not inbounds of the only object it can point to
-   |                       ^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer at offset 32 is out-of-bounds
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-help: ALLOC was allocated here:
-  --> $DIR/ptr_offset_ptr_plus_0.rs:LL:CC
-   |
-LL |     let x = Box::into_raw(Box::new(0u32));
-   |                           ^^^^^^^^^^^^^^
-   = note: BACKTRACE (of the first span):
-   = note: inside `main` at $DIR/ptr_offset_ptr_plus_0.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/intrinsics/write_bytes_null.rs b/src/tools/miri/tests/fail/intrinsics/write_bytes_null.rs
deleted file mode 100644
index 2f46c82..0000000
--- a/src/tools/miri/tests/fail/intrinsics/write_bytes_null.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-#![feature(intrinsics)]
-
-// Directly call intrinsic to avoid debug assertions in libstd
-extern "rust-intrinsic" {
-    fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
-}
-
-fn main() {
-    unsafe { write_bytes::<u8>(std::ptr::null_mut(), 0, 0) }; //~ ERROR: memory access failed: null pointer is a dangling pointer
-}
diff --git a/src/tools/miri/tests/fail/intrinsics/write_bytes_null.stderr b/src/tools/miri/tests/fail/intrinsics/write_bytes_null.stderr
deleted file mode 100644
index def1809..0000000
--- a/src/tools/miri/tests/fail/intrinsics/write_bytes_null.stderr
+++ /dev/null
@@ -1,15 +0,0 @@
-error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance)
-  --> $DIR/write_bytes_null.rs:LL:CC
-   |
-LL |     unsafe { write_bytes::<u8>(std::ptr::null_mut(), 0, 0) };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-   = note: BACKTRACE:
-   = note: inside `main` at $DIR/write_bytes_null.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs
index 97a7010..a20539e 100644
--- a/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs
+++ b/src/tools/miri/tests/fail/shims/backtrace/bad-backtrace-decl.rs
@@ -5,7 +5,7 @@
 
 fn main() {
     let frames = unsafe { miri_get_backtrace(0) };
-    for frame in frames.into_iter() {
+    for frame in frames.iter() {
         unsafe {
             miri_resolve_frame(*frame, 0); //~ ERROR: Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields
         }
diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs
index 7cdc15c..9fabdd8 100644
--- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs
+++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_callee_ret.rs
@@ -2,15 +2,15 @@
 #![feature(core_intrinsics, custom_mir)]
 
 use std::intrinsics::mir::*;
-use std::num::NonZeroU32;
+use std::num::NonZero;
 use std::ptr;
 
-// This function supposedly returns a NonZeroU32, but actually returns something invalid in a way that
-// never materializes a bad NonZeroU32 value: we take a pointer to the return place and cast the pointer
+// This function supposedly returns a `NonZero<u32>`, but actually returns something invalid in a way that
+// never materializes a bad `NonZero<u32>` value: we take a pointer to the return place and cast the pointer
 // type. That way we never get an "invalid value constructed" error inside the function, it can
 // only possibly be detected when the return value is passed to the caller.
 #[custom_mir(dialect = "runtime", phase = "optimized")]
-fn f() -> NonZeroU32 {
+fn f() -> NonZero<u32> {
     mir! {
         {
             let tmp = ptr::addr_of_mut!(RET);
@@ -22,7 +22,7 @@
 }
 
 fn main() {
-    let f: fn() -> u32 = unsafe { std::mem::transmute(f as fn() -> NonZeroU32) };
-    // There's a NonZeroU32-to-u32 transmute happening here
+    let f: fn() -> u32 = unsafe { std::mem::transmute(f as fn() -> NonZero<u32>) };
+    // There's a `NonZero<u32>` to `u32` transmute happening here.
     f(); //~ERROR: expected something greater or equal to 1
 }
diff --git a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs
index 3a87bb7..7ca26bf 100644
--- a/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs
+++ b/src/tools/miri/tests/fail/validity/cast_fn_ptr_invalid_caller_arg.rs
@@ -2,24 +2,24 @@
 #![feature(core_intrinsics, custom_mir)]
 
 use std::intrinsics::mir::*;
-use std::num::NonZeroU32;
+use std::num::NonZero;
 use std::ptr;
 
 fn f(c: u32) {
     println!("{c}");
 }
 
-// Call that function in a bad way, with an invalid NonZeroU32, but without
-// ever materializing this as a NonZeroU32 value outside the call itself.
+// Call that function in a bad way, with an invalid `NonZero<u32>`, but without
+// ever materializing this as a `NonZero<u32>` value outside the call itself.
 #[custom_mir(dialect = "runtime", phase = "optimized")]
-fn call(f: fn(NonZeroU32)) {
+fn call(f: fn(NonZero<u32>)) {
     mir! {
         let _res: ();
         {
             let c = 0;
             let tmp = ptr::addr_of!(c);
-            let ptr = tmp as *const NonZeroU32;
-            // The call site now is a NonZeroU32-to-u32 transmute.
+            let ptr = tmp as *const NonZero<u32>;
+            // The call site now is a `NonZero<u32>` to `u32` transmute.
             Call(_res = f(*ptr), ReturnTo(retblock), UnwindContinue()) //~ERROR: expected something greater or equal to 1
         }
         retblock = {
@@ -29,6 +29,6 @@
 }
 
 fn main() {
-    let f: fn(NonZeroU32) = unsafe { std::mem::transmute(f as fn(u32)) };
+    let f: fn(NonZero<u32>) = unsafe { std::mem::transmute(f as fn(u32)) };
     call(f);
 }
diff --git a/src/tools/miri/tests/fail/zst2.rs b/src/tools/miri/tests/fail/zst2.rs
deleted file mode 100644
index 04218c2..0000000
--- a/src/tools/miri/tests/fail/zst2.rs
+++ /dev/null
@@ -1,12 +0,0 @@
-fn main() {
-    // Not using the () type here, as writes of that type do not even have MIR generated.
-    // Also not assigning directly as that's array initialization, not assignment.
-    let zst_val = [1u8; 0];
-
-    // make sure ZST accesses are checked against being "truly" dangling pointers
-    // (into deallocated allocations).
-    let mut x_box = Box::new(1u8);
-    let x = &mut *x_box as *mut _ as *mut [u8; 0];
-    drop(x_box);
-    unsafe { *x = zst_val }; //~ ERROR: has been freed
-}
diff --git a/src/tools/miri/tests/fail/zst2.stderr b/src/tools/miri/tests/fail/zst2.stderr
deleted file mode 100644
index b3f65e7..0000000
--- a/src/tools/miri/tests/fail/zst2.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error: Undefined Behavior: memory access failed: ALLOC has been freed, so this pointer is dangling
-  --> $DIR/zst2.rs:LL:CC
-   |
-LL |     unsafe { *x = zst_val };
-   |              ^^^^^^^^^^^^ memory access failed: ALLOC has been freed, so this pointer is dangling
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-help: ALLOC was allocated here:
-  --> $DIR/zst2.rs:LL:CC
-   |
-LL |     let mut x_box = Box::new(1u8);
-   |                     ^^^^^^^^^^^^^
-help: ALLOC was deallocated here:
-  --> $DIR/zst2.rs:LL:CC
-   |
-LL |     drop(x_box);
-   |     ^^^^^^^^^^^
-   = note: BACKTRACE (of the first span):
-   = note: inside `main` at $DIR/zst2.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/zst3.rs b/src/tools/miri/tests/fail/zst3.rs
deleted file mode 100644
index 454bef2..0000000
--- a/src/tools/miri/tests/fail/zst3.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-fn main() {
-    // Not using the () type here, as writes of that type do not even have MIR generated.
-    // Also not assigning directly as that's array initialization, not assignment.
-    let zst_val = [1u8; 0];
-
-    // make sure ZST accesses are checked against being "truly" dangling pointers
-    // (that are out-of-bounds).
-    let mut x_box = Box::new(1u8);
-    let x = (&mut *x_box as *mut u8).wrapping_offset(1);
-    // This one is just "at the edge", but still okay
-    unsafe { *(x as *mut [u8; 0]) = zst_val };
-    // One byte further is OOB.
-    let x = x.wrapping_offset(1);
-    unsafe { *(x as *mut [u8; 0]) = zst_val }; //~ ERROR: out-of-bounds
-}
diff --git a/src/tools/miri/tests/fail/zst3.stderr b/src/tools/miri/tests/fail/zst3.stderr
deleted file mode 100644
index b9495fb..0000000
--- a/src/tools/miri/tests/fail/zst3.stderr
+++ /dev/null
@@ -1,20 +0,0 @@
-error: Undefined Behavior: memory access failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds
-  --> $DIR/zst3.rs:LL:CC
-   |
-LL |     unsafe { *(x as *mut [u8; 0]) = zst_val };
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds
-   |
-   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
-   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
-help: ALLOC was allocated here:
-  --> $DIR/zst3.rs:LL:CC
-   |
-LL |     let mut x_box = Box::new(1u8);
-   |                     ^^^^^^^^^^^^^
-   = note: BACKTRACE (of the first span):
-   = note: inside `main` at $DIR/zst3.rs:LL:CC
-
-note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
-
-error: aborting due to 1 previous error
-
diff --git a/src/tools/miri/tests/fail/zst1.rs b/src/tools/miri/tests/fail/zst_local_oob.rs
similarity index 100%
rename from src/tools/miri/tests/fail/zst1.rs
rename to src/tools/miri/tests/fail/zst_local_oob.rs
diff --git a/src/tools/miri/tests/fail/zst1.stderr b/src/tools/miri/tests/fail/zst_local_oob.stderr
similarity index 88%
rename from src/tools/miri/tests/fail/zst1.stderr
rename to src/tools/miri/tests/fail/zst_local_oob.stderr
index cda837d..ba1ccaa 100644
--- a/src/tools/miri/tests/fail/zst1.stderr
+++ b/src/tools/miri/tests/fail/zst_local_oob.stderr
@@ -1,5 +1,5 @@
 error: Undefined Behavior: memory access failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds
-  --> $DIR/zst1.rs:LL:CC
+  --> $DIR/zst_local_oob.rs:LL:CC
    |
 LL |     let _val = unsafe { *x };
    |                         ^^ memory access failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds
@@ -7,7 +7,7 @@
    = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
    = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
    = note: BACKTRACE:
-   = note: inside `main` at $DIR/zst1.rs:LL:CC
+   = note: inside `main` at $DIR/zst_local_oob.rs:LL:CC
 
 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
 
diff --git a/src/tools/miri/tests/extern-so/fail/function_not_in_so.rs b/src/tools/miri/tests/native-lib/fail/function_not_in_so.rs
similarity index 100%
rename from src/tools/miri/tests/extern-so/fail/function_not_in_so.rs
rename to src/tools/miri/tests/native-lib/fail/function_not_in_so.rs
diff --git a/src/tools/miri/tests/extern-so/fail/function_not_in_so.stderr b/src/tools/miri/tests/native-lib/fail/function_not_in_so.stderr
similarity index 100%
rename from src/tools/miri/tests/extern-so/fail/function_not_in_so.stderr
rename to src/tools/miri/tests/native-lib/fail/function_not_in_so.stderr
diff --git a/src/tools/miri/tests/extern-so/libtest.map b/src/tools/miri/tests/native-lib/libtest.map
similarity index 100%
rename from src/tools/miri/tests/extern-so/libtest.map
rename to src/tools/miri/tests/native-lib/libtest.map
diff --git a/src/tools/miri/tests/extern-so/pass/call_extern_c_fn.rs b/src/tools/miri/tests/native-lib/pass/call_extern_c_fn.rs
similarity index 100%
rename from src/tools/miri/tests/extern-so/pass/call_extern_c_fn.rs
rename to src/tools/miri/tests/native-lib/pass/call_extern_c_fn.rs
diff --git a/src/tools/miri/tests/extern-so/pass/call_extern_c_fn.stdout b/src/tools/miri/tests/native-lib/pass/call_extern_c_fn.stdout
similarity index 100%
rename from src/tools/miri/tests/extern-so/pass/call_extern_c_fn.stdout
rename to src/tools/miri/tests/native-lib/pass/call_extern_c_fn.stdout
diff --git a/src/tools/miri/tests/extern-so/test.c b/src/tools/miri/tests/native-lib/test.c
similarity index 100%
rename from src/tools/miri/tests/extern-so/test.c
rename to src/tools/miri/tests/native-lib/test.c
diff --git a/src/tools/miri/tests/panic/unsupported_syscall.rs b/src/tools/miri/tests/panic/unsupported_syscall.rs
index 31d666e..30f9da5 100644
--- a/src/tools/miri/tests/panic/unsupported_syscall.rs
+++ b/src/tools/miri/tests/panic/unsupported_syscall.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: no `syscall` on Windows
 //@ignore-target-apple: `syscall` is not supported on macOS
 //@compile-flags: -Zmiri-panic-on-unsupported
 
diff --git a/src/tools/miri/tests/pass-dep/calloc.rs b/src/tools/miri/tests/pass-dep/calloc.rs
deleted file mode 100644
index 62ab63c..0000000
--- a/src/tools/miri/tests/pass-dep/calloc.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-//@ignore-target-windows: No libc on Windows
-
-use core::slice;
-
-fn main() {
-    unsafe {
-        let p1 = libc::calloc(0, 0);
-        assert!(p1.is_null());
-
-        let p2 = libc::calloc(20, 0);
-        assert!(p2.is_null());
-
-        let p3 = libc::calloc(0, 20);
-        assert!(p3.is_null());
-
-        let p4 = libc::calloc(4, 8);
-        assert!(!p4.is_null());
-        let slice = slice::from_raw_parts(p4 as *const u8, 4 * 8);
-        assert_eq!(&slice, &[0_u8; 4 * 8]);
-        libc::free(p4);
-    }
-}
diff --git a/src/tools/miri/tests/pass-dep/shims/env-cleanup-data-race.rs b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs
similarity index 92%
rename from src/tools/miri/tests/pass-dep/shims/env-cleanup-data-race.rs
rename to src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs
index 5c29a1b..86a47ba 100644
--- a/src/tools/miri/tests/pass-dep/shims/env-cleanup-data-race.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/env-cleanup-data-race.rs
@@ -1,5 +1,5 @@
 //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No libc env support on Windows
 
 use std::ffi::CStr;
 use std::thread;
diff --git a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs
index f362caa..d758168 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 //@ignore-target-apple: pthread_condattr_setclock is not supported on MacOS.
 //@compile-flags: -Zmiri-disable-isolation
 
diff --git a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs
index 66c0895..f1a3c5d 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/libc_pthread_cond_timedwait_isolated.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 //@ignore-target-apple: pthread_condattr_setclock is not supported on MacOS.
 
 /// Test that conditional variable timeouts are working properly
diff --git a/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs b/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs
index ae87474..0eaab96 100644
--- a/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs
+++ b/src/tools/miri/tests/pass-dep/concurrency/tls_pthread_drop_order.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 //! Test that pthread_key destructors are run in the right order.
 //! Note that these are *not* used by actual `thread_local!` on Linux! Those use
 //! `thread_local_dtor::register_dtor` from the stdlib instead. In Miri this hits the fallback path
diff --git a/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs b/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs
index 716119a..1198168 100644
--- a/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs
+++ b/src/tools/miri/tests/pass-dep/extra_fn_ptr_gc.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No `dlsym` on Windows
 //@compile-flags: -Zmiri-permissive-provenance
 
 #[path = "../utils/mod.rs"]
diff --git a/src/tools/miri/tests/pass-dep/getrandom.rs b/src/tools/miri/tests/pass-dep/getrandom.rs
index c0d9296..53de3af 100644
--- a/src/tools/miri/tests/pass-dep/getrandom.rs
+++ b/src/tools/miri/tests/pass-dep/getrandom.rs
@@ -1,8 +1,9 @@
 // mac-os `getrandom_01` does some pointer shenanigans
 //@compile-flags: -Zmiri-permissive-provenance
+//@revisions: isolation no_isolation
+//@[no_isolation]compile-flags: -Zmiri-disable-isolation
 
 /// Test direct calls of getrandom 0.1 and 0.2.
-/// Make sure they work even with isolation enabled (i.e., we do not hit a file-based fallback path).
 fn main() {
     let mut data = vec![0; 16];
     getrandom_01::getrandom(&mut data).unwrap();
diff --git a/src/tools/miri/tests/pass-dep/shims/fcntl_f-fullfsync_apple.rs b/src/tools/miri/tests/pass-dep/libc/fcntl_f-fullfsync_apple.rs
similarity index 100%
rename from src/tools/miri/tests/pass-dep/shims/fcntl_f-fullfsync_apple.rs
rename to src/tools/miri/tests/pass-dep/libc/fcntl_f-fullfsync_apple.rs
diff --git a/src/tools/miri/tests/pass-dep/shims/fcntl_f-fullfsync_apple.stderr b/src/tools/miri/tests/pass-dep/libc/fcntl_f-fullfsync_apple.stderr
similarity index 100%
rename from src/tools/miri/tests/pass-dep/shims/fcntl_f-fullfsync_apple.stderr
rename to src/tools/miri/tests/pass-dep/libc/fcntl_f-fullfsync_apple.stderr
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-fs-readlink.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-readlink.rs
new file mode 100644
index 0000000..d72edd7
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-readlink.rs
@@ -0,0 +1,51 @@
+// Symlink tests are separate since they don't in general work on a Windows host.
+//@ignore-host-windows: creating symlinks requires admin permissions on Windows
+//@ignore-target-windows: File handling is not implemented yet
+//@compile-flags: -Zmiri-disable-isolation
+
+use std::ffi::CString;
+use std::io::{Error, ErrorKind};
+use std::os::unix::ffi::OsStrExt;
+
+#[path = "../../utils/mod.rs"]
+mod utils;
+
+fn main() {
+    let bytes = b"Hello, World!\n";
+    let path = utils::prepare_with_content("miri_test_fs_link_target.txt", bytes);
+    let expected_path = path.as_os_str().as_bytes();
+
+    let symlink_path = utils::prepare("miri_test_fs_symlink.txt");
+    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
+
+    // Test that the expected string gets written to a buffer of proper
+    // length, and that a trailing null byte is not written.
+    let symlink_c_str = CString::new(symlink_path.as_os_str().as_bytes()).unwrap();
+    let symlink_c_ptr = symlink_c_str.as_ptr();
+
+    // Make the buf one byte larger than it needs to be,
+    // and check that the last byte is not overwritten.
+    let mut large_buf = vec![0xFF; expected_path.len() + 1];
+    let res =
+        unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) };
+    // Check that the resolved path was properly written into the buf.
+    assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path);
+    assert_eq!(large_buf.last(), Some(&0xFF));
+    assert_eq!(res, large_buf.len() as isize - 1);
+
+    // Test that the resolved path is truncated if the provided buffer
+    // is too small.
+    let mut small_buf = [0u8; 2];
+    let res =
+        unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) };
+    assert_eq!(small_buf, &expected_path[..small_buf.len()]);
+    assert_eq!(res, small_buf.len() as isize);
+
+    // Test that we report a proper error for a missing path.
+    let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap();
+    let res = unsafe {
+        libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len())
+    };
+    assert_eq!(res, -1);
+    assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound);
+}
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs
similarity index 93%
rename from src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs
rename to src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs
index 5185db0..088a632 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: no libc on Windows
+//@ignore-target-windows: File handling is not implemented yet
 //@compile-flags: -Zmiri-isolation-error=warn-nobacktrace
 //@normalize-stderr-test: "(stat(x)?)" -> "$$STAT"
 
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.stderr b/src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.stderr
similarity index 100%
rename from src/tools/miri/tests/pass-dep/shims/libc-fs-with-isolation.stderr
rename to src/tools/miri/tests/pass-dep/libc/libc-fs-with-isolation.stderr
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs.rs b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
similarity index 78%
rename from src/tools/miri/tests/pass-dep/shims/libc-fs.rs
rename to src/tools/miri/tests/pass-dep/libc/libc-fs.rs
index 0dd849a..80c9757 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-fs.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-fs.rs
@@ -1,11 +1,11 @@
-//@ignore-target-windows: no libc on Windows
+//@ignore-target-windows: File handling is not implemented yet
 //@compile-flags: -Zmiri-disable-isolation
 
 #![feature(io_error_more)]
 #![feature(io_error_uncategorized)]
 
 use std::ffi::{CStr, CString, OsString};
-use std::fs::{canonicalize, remove_dir_all, remove_file, File};
+use std::fs::{canonicalize, remove_file, File};
 use std::io::{Error, ErrorKind, Write};
 use std::os::unix::ffi::OsStrExt;
 use std::os::unix::io::AsRawFd;
@@ -21,7 +21,6 @@
     test_ftruncate::<libc::off_t>(libc::ftruncate);
     #[cfg(target_os = "linux")]
     test_ftruncate::<libc::off64_t>(libc::ftruncate64);
-    test_readlink();
     test_file_open_unix_allow_two_args();
     test_file_open_unix_needs_three_args();
     test_file_open_unix_extra_third_arg();
@@ -38,33 +37,8 @@
     test_isatty();
 }
 
-/// Prepare: compute filename and make sure the file does not exist.
-fn prepare(filename: &str) -> PathBuf {
-    let path = utils::tmp().join(filename);
-    // Clean the paths for robustness.
-    remove_file(&path).ok();
-    path
-}
-
-/// Prepare directory: compute directory name and make sure it does not exist.
-#[allow(unused)]
-fn prepare_dir(dirname: &str) -> PathBuf {
-    let path = utils::tmp().join(&dirname);
-    // Clean the directory for robustness.
-    remove_dir_all(&path).ok();
-    path
-}
-
-/// Prepare like above, and also write some initial content to the file.
-fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf {
-    let path = prepare(filename);
-    let mut file = File::create(&path).unwrap();
-    file.write(content).unwrap();
-    path
-}
-
 fn test_file_open_unix_allow_two_args() {
-    let path = prepare_with_content("test_file_open_unix_allow_two_args.txt", &[]);
+    let path = utils::prepare_with_content("test_file_open_unix_allow_two_args.txt", &[]);
 
     let mut name = path.into_os_string();
     name.push("\0");
@@ -73,7 +47,7 @@
 }
 
 fn test_file_open_unix_needs_three_args() {
-    let path = prepare_with_content("test_file_open_unix_needs_three_args.txt", &[]);
+    let path = utils::prepare_with_content("test_file_open_unix_needs_three_args.txt", &[]);
 
     let mut name = path.into_os_string();
     name.push("\0");
@@ -82,7 +56,7 @@
 }
 
 fn test_file_open_unix_extra_third_arg() {
-    let path = prepare_with_content("test_file_open_unix_extra_third_arg.txt", &[]);
+    let path = utils::prepare_with_content("test_file_open_unix_extra_third_arg.txt", &[]);
 
     let mut name = path.into_os_string();
     name.push("\0");
@@ -106,49 +80,9 @@
     assert!(canonicalize(too_long).is_err());
 }
 
-fn test_readlink() {
-    let bytes = b"Hello, World!\n";
-    let path = prepare_with_content("miri_test_fs_link_target.txt", bytes);
-    let expected_path = path.as_os_str().as_bytes();
-
-    let symlink_path = prepare("miri_test_fs_symlink.txt");
-    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
-
-    // Test that the expected string gets written to a buffer of proper
-    // length, and that a trailing null byte is not written.
-    let symlink_c_str = CString::new(symlink_path.as_os_str().as_bytes()).unwrap();
-    let symlink_c_ptr = symlink_c_str.as_ptr();
-
-    // Make the buf one byte larger than it needs to be,
-    // and check that the last byte is not overwritten.
-    let mut large_buf = vec![0xFF; expected_path.len() + 1];
-    let res =
-        unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) };
-    // Check that the resolved path was properly written into the buf.
-    assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path);
-    assert_eq!(large_buf.last(), Some(&0xFF));
-    assert_eq!(res, large_buf.len() as isize - 1);
-
-    // Test that the resolved path is truncated if the provided buffer
-    // is too small.
-    let mut small_buf = [0u8; 2];
-    let res =
-        unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) };
-    assert_eq!(small_buf, &expected_path[..small_buf.len()]);
-    assert_eq!(res, small_buf.len() as isize);
-
-    // Test that we report a proper error for a missing path.
-    let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap();
-    let res = unsafe {
-        libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len())
-    };
-    assert_eq!(res, -1);
-    assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound);
-}
-
 fn test_rename() {
-    let path1 = prepare("miri_test_libc_fs_source.txt");
-    let path2 = prepare("miri_test_libc_fs_rename_destination.txt");
+    let path1 = utils::prepare("miri_test_libc_fs_source.txt");
+    let path2 = utils::prepare("miri_test_libc_fs_rename_destination.txt");
 
     let file = File::create(&path1).unwrap();
     drop(file);
@@ -178,7 +112,7 @@
     // https://docs.rs/libc/latest/i686-unknown-linux-gnu/libc/type.off_t.html
 
     let bytes = b"hello";
-    let path = prepare("miri_test_libc_fs_ftruncate.txt");
+    let path = utils::prepare("miri_test_libc_fs_ftruncate.txt");
     let mut file = File::create(&path).unwrap();
     file.write(bytes).unwrap();
     file.sync_all().unwrap();
@@ -209,7 +143,7 @@
 fn test_o_tmpfile_flag() {
     use std::fs::{create_dir, OpenOptions};
     use std::os::unix::fs::OpenOptionsExt;
-    let dir_path = prepare_dir("miri_test_fs_dir");
+    let dir_path = utils::prepare_dir("miri_test_fs_dir");
     create_dir(&dir_path).unwrap();
     // test that the `O_TMPFILE` custom flag gracefully errors instead of stopping execution
     assert_eq!(
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs.stderr b/src/tools/miri/tests/pass-dep/libc/libc-fs.stderr
similarity index 100%
rename from src/tools/miri/tests/pass-dep/shims/libc-fs.stderr
rename to src/tools/miri/tests/pass-dep/libc/libc-fs.stderr
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-fs.stdout b/src/tools/miri/tests/pass-dep/libc/libc-fs.stdout
similarity index 100%
rename from src/tools/miri/tests/pass-dep/shims/libc-fs.stdout
rename to src/tools/miri/tests/pass-dep/libc/libc-fs.stdout
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-mem.rs b/src/tools/miri/tests/pass-dep/libc/libc-mem.rs
new file mode 100644
index 0000000..aa383a9
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/libc/libc-mem.rs
@@ -0,0 +1,302 @@
+#![feature(strict_provenance, pointer_is_aligned_to)]
+use std::{mem, ptr, slice};
+
+fn test_memcpy() {
+    unsafe {
+        let src = [1i8, 2, 3];
+        let dest = libc::calloc(3, 1);
+        libc::memcpy(dest, src.as_ptr() as *const libc::c_void, 3);
+        let slc = std::slice::from_raw_parts(dest as *const i8, 3);
+        assert_eq!(*slc, [1i8, 2, 3]);
+        libc::free(dest);
+    }
+
+    unsafe {
+        let src = [1i8, 2, 3];
+        let dest = libc::calloc(4, 1);
+        libc::memcpy(dest, src.as_ptr() as *const libc::c_void, 3);
+        let slc = std::slice::from_raw_parts(dest as *const i8, 4);
+        assert_eq!(*slc, [1i8, 2, 3, 0]);
+        libc::free(dest);
+    }
+
+    unsafe {
+        let src = 123_i32;
+        let mut dest = 0_i32;
+        libc::memcpy(
+            &mut dest as *mut i32 as *mut libc::c_void,
+            &src as *const i32 as *const libc::c_void,
+            mem::size_of::<i32>(),
+        );
+        assert_eq!(dest, src);
+    }
+
+    unsafe {
+        let src = Some(123);
+        let mut dest: Option<i32> = None;
+        libc::memcpy(
+            &mut dest as *mut Option<i32> as *mut libc::c_void,
+            &src as *const Option<i32> as *const libc::c_void,
+            mem::size_of::<Option<i32>>(),
+        );
+        assert_eq!(dest, src);
+    }
+
+    unsafe {
+        let src = &123;
+        let mut dest = &42;
+        libc::memcpy(
+            &mut dest as *mut &'static i32 as *mut libc::c_void,
+            &src as *const &'static i32 as *const libc::c_void,
+            mem::size_of::<&'static i32>(),
+        );
+        assert_eq!(*dest, 123);
+    }
+}
+
+fn test_strcpy() {
+    use std::ffi::{CStr, CString};
+
+    // case: src_size equals dest_size
+    unsafe {
+        let src = CString::new("rust").unwrap();
+        let size = src.as_bytes_with_nul().len();
+        let dest = libc::malloc(size);
+        libc::strcpy(dest as *mut libc::c_char, src.as_ptr());
+        assert_eq!(CStr::from_ptr(dest as *const libc::c_char), src.as_ref());
+        libc::free(dest);
+    }
+
+    // case: src_size is less than dest_size
+    unsafe {
+        let src = CString::new("rust").unwrap();
+        let size = src.as_bytes_with_nul().len();
+        let dest = libc::malloc(size + 1);
+        libc::strcpy(dest as *mut libc::c_char, src.as_ptr());
+        assert_eq!(CStr::from_ptr(dest as *const libc::c_char), src.as_ref());
+        libc::free(dest);
+    }
+}
+
+fn test_malloc() {
+    // Test that small allocations sometimes *are* not very aligned.
+    let saw_unaligned = (0..64).any(|_| unsafe {
+        let p = libc::malloc(3);
+        libc::free(p);
+        (p as usize) % 4 != 0 // find any that this is *not* 4-aligned
+    });
+    assert!(saw_unaligned);
+
+    unsafe {
+        let p1 = libc::malloc(20);
+        p1.write_bytes(0u8, 20);
+
+        // old size < new size
+        let p2 = libc::realloc(p1, 40);
+        let slice = slice::from_raw_parts(p2 as *const u8, 20);
+        assert_eq!(&slice, &[0_u8; 20]);
+
+        // old size == new size
+        let p3 = libc::realloc(p2, 40);
+        let slice = slice::from_raw_parts(p3 as *const u8, 20);
+        assert_eq!(&slice, &[0_u8; 20]);
+
+        // old size > new size
+        let p4 = libc::realloc(p3, 10);
+        let slice = slice::from_raw_parts(p4 as *const u8, 10);
+        assert_eq!(&slice, &[0_u8; 10]);
+
+        libc::free(p4);
+    }
+
+    unsafe {
+        // Realloc with size 0 is okay for the null pointer (and acts like `malloc(0)`)
+        let p2 = libc::realloc(ptr::null_mut(), 0);
+        assert!(!p2.is_null());
+        libc::free(p2);
+    }
+
+    unsafe {
+        let p1 = libc::realloc(ptr::null_mut(), 20);
+        assert!(!p1.is_null());
+
+        libc::free(p1);
+    }
+}
+
+fn test_calloc() {
+    unsafe {
+        let p1 = libc::calloc(0, 0);
+        assert!(!p1.is_null());
+        libc::free(p1);
+
+        let p2 = libc::calloc(20, 0);
+        assert!(!p2.is_null());
+        libc::free(p2);
+
+        let p3 = libc::calloc(0, 20);
+        assert!(!p3.is_null());
+        libc::free(p3);
+
+        let p4 = libc::calloc(4, 8);
+        assert!(!p4.is_null());
+        let slice = slice::from_raw_parts(p4 as *const u8, 4 * 8);
+        assert_eq!(&slice, &[0_u8; 4 * 8]);
+        libc::free(p4);
+    }
+}
+
+#[cfg(not(target_os = "windows"))]
+fn test_memalign() {
+    for _ in 0..16 {
+        // A normal allocation.
+        unsafe {
+            let mut ptr: *mut libc::c_void = ptr::null_mut();
+            let align = 8;
+            let size = 64;
+            assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
+            assert!(!ptr.is_null());
+            assert!(ptr.is_aligned_to(align));
+            ptr.cast::<u8>().write_bytes(1, size);
+            libc::free(ptr);
+        }
+
+        // Align > size.
+        unsafe {
+            let mut ptr: *mut libc::c_void = ptr::null_mut();
+            let align = 64;
+            let size = 8;
+            assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
+            assert!(!ptr.is_null());
+            assert!(ptr.is_aligned_to(align));
+            ptr.cast::<u8>().write_bytes(1, size);
+            libc::free(ptr);
+        }
+
+        // Size not multiple of align
+        unsafe {
+            let mut ptr: *mut libc::c_void = ptr::null_mut();
+            let align = 16;
+            let size = 31;
+            assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
+            assert!(!ptr.is_null());
+            assert!(ptr.is_aligned_to(align));
+            ptr.cast::<u8>().write_bytes(1, size);
+            libc::free(ptr);
+        }
+
+        // Size == 0
+        unsafe {
+            let mut ptr: *mut libc::c_void = ptr::null_mut();
+            let align = 64;
+            let size = 0;
+            assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
+            // Non-null pointer is returned if size == 0.
+            // (This is not a guarantee, it just reflects our current behavior.)
+            assert!(!ptr.is_null());
+            assert!(ptr.is_aligned_to(align));
+            libc::free(ptr);
+        }
+    }
+
+    // Non-power of 2 align
+    unsafe {
+        let mut ptr: *mut libc::c_void = ptr::without_provenance_mut(0x1234567);
+        let align = 15;
+        let size = 8;
+        assert_eq!(libc::posix_memalign(&mut ptr, align, size), libc::EINVAL);
+        // The pointer is not modified on failure, posix_memalign(3) says:
+        // > On Linux (and other systems), posix_memalign() does  not  modify  memptr  on failure.
+        // > A requirement standardizing this behavior was added in POSIX.1-2008 TC2.
+        assert_eq!(ptr.addr(), 0x1234567);
+    }
+
+    // Too small align (smaller than ptr)
+    unsafe {
+        let mut ptr: *mut libc::c_void = ptr::without_provenance_mut(0x1234567);
+        let align = std::mem::size_of::<usize>() / 2;
+        let size = 8;
+        assert_eq!(libc::posix_memalign(&mut ptr, align, size), libc::EINVAL);
+        // The pointer is not modified on failure, posix_memalign(3) says:
+        // > On Linux (and other systems), posix_memalign() does  not  modify  memptr  on failure.
+        // > A requirement standardizing this behavior was added in POSIX.1-2008 TC2.
+        assert_eq!(ptr.addr(), 0x1234567);
+    }
+}
+
+#[cfg(not(any(
+    target_os = "windows",
+    target_os = "macos",
+    target_os = "illumos",
+    target_os = "solaris",
+    target_os = "wasi",
+)))]
+fn test_reallocarray() {
+    unsafe {
+        let mut p = libc::reallocarray(std::ptr::null_mut(), 4096, 2);
+        assert!(!p.is_null());
+        libc::free(p);
+        p = libc::malloc(16);
+        let r = libc::reallocarray(p, 2, 32);
+        assert!(!r.is_null());
+        libc::free(r);
+    }
+}
+
+#[cfg(not(target_os = "windows"))]
+fn test_aligned_alloc() {
+    // libc doesn't have this function (https://github.com/rust-lang/libc/issues/3689),
+    // so we declare it ourselves.
+    extern "C" {
+        fn aligned_alloc(alignment: libc::size_t, size: libc::size_t) -> *mut libc::c_void;
+    }
+    // size not a multiple of the alignment
+    unsafe {
+        let p = aligned_alloc(16, 3);
+        assert_eq!(p, ptr::null_mut());
+    }
+
+    // alignment not power of 2
+    unsafe {
+        let p = aligned_alloc(63, 8);
+        assert_eq!(p, ptr::null_mut());
+    }
+
+    // repeated tests on correct alignment/size
+    for _ in 0..16 {
+        // alignment 1, size 4 should succeed and actually must align to 4 (because C says so...)
+        unsafe {
+            let p = aligned_alloc(1, 4);
+            assert!(!p.is_null());
+            assert!(p.is_aligned_to(4));
+            libc::free(p);
+        }
+
+        unsafe {
+            let p = aligned_alloc(64, 64);
+            assert!(!p.is_null());
+            assert!(p.is_aligned_to(64));
+            libc::free(p);
+        }
+    }
+}
+
+fn main() {
+    test_malloc();
+    test_calloc();
+    #[cfg(not(target_os = "windows"))]
+    test_memalign();
+    #[cfg(not(any(
+        target_os = "windows",
+        target_os = "macos",
+        target_os = "illumos",
+        target_os = "solaris",
+        target_os = "wasi",
+    )))]
+    test_reallocarray();
+    #[cfg(not(target_os = "windows"))]
+    test_aligned_alloc();
+
+    test_memcpy();
+    test_strcpy();
+}
diff --git a/src/tools/miri/tests/pass-dep/libc/libc-misc.rs b/src/tools/miri/tests/pass-dep/libc/libc-misc.rs
new file mode 100644
index 0000000..f7e1d9f
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/libc/libc-misc.rs
@@ -0,0 +1,86 @@
+//@ignore-target-windows: only very limited libc on Windows
+//@compile-flags: -Zmiri-disable-isolation
+#![feature(io_error_more)]
+#![feature(pointer_is_aligned_to)]
+#![feature(strict_provenance)]
+
+use std::mem::transmute;
+
+/// Tests whether each thread has its own `__errno_location`.
+fn test_thread_local_errno() {
+    #[cfg(any(target_os = "illumos", target_os = "solaris"))]
+    use libc::___errno as __errno_location;
+    #[cfg(target_os = "android")]
+    use libc::__errno as __errno_location;
+    #[cfg(target_os = "linux")]
+    use libc::__errno_location;
+    #[cfg(any(target_os = "freebsd", target_os = "macos"))]
+    use libc::__error as __errno_location;
+
+    unsafe {
+        *__errno_location() = 0xBEEF;
+        std::thread::spawn(|| {
+            assert_eq!(*__errno_location(), 0);
+            *__errno_location() = 0xBAD1DEA;
+            assert_eq!(*__errno_location(), 0xBAD1DEA);
+        })
+        .join()
+        .unwrap();
+        assert_eq!(*__errno_location(), 0xBEEF);
+    }
+}
+
+fn test_environ() {
+    // Just a smoke test for now, checking that the extern static exists.
+    extern "C" {
+        static mut environ: *const *const libc::c_char;
+    }
+
+    unsafe {
+        let mut e = environ;
+        // Iterate to the end.
+        while !(*e).is_null() {
+            e = e.add(1);
+        }
+    }
+}
+
+#[cfg(target_os = "linux")]
+fn test_sigrt() {
+    let min = libc::SIGRTMIN();
+    let max = libc::SIGRTMAX();
+
+    // "The Linux kernel supports a range of 33 different real-time
+    // signals, numbered 32 to 64"
+    assert!(min >= 32);
+    assert!(max >= 32);
+    assert!(min <= 64);
+    assert!(max <= 64);
+
+    // "POSIX.1-2001 requires that an implementation support at least
+    // _POSIX_RTSIG_MAX (8) real-time signals."
+    assert!(min < max);
+    assert!(max - min >= 8)
+}
+
+fn test_dlsym() {
+    let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"notasymbol\0".as_ptr().cast()) };
+    assert!(addr as usize == 0);
+
+    let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"isatty\0".as_ptr().cast()) };
+    assert!(addr as usize != 0);
+    let isatty: extern "C" fn(i32) -> i32 = unsafe { transmute(addr) };
+    assert_eq!(isatty(999), 0);
+    let errno = std::io::Error::last_os_error().raw_os_error().unwrap();
+    assert_eq!(errno, libc::EBADF);
+}
+
+fn main() {
+    test_thread_local_errno();
+    test_environ();
+
+    test_dlsym();
+
+    #[cfg(target_os = "linux")]
+    test_sigrt();
+}
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-random.rs b/src/tools/miri/tests/pass-dep/libc/libc-random.rs
similarity index 100%
rename from src/tools/miri/tests/pass-dep/shims/libc-random.rs
rename to src/tools/miri/tests/pass-dep/libc/libc-random.rs
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-time.rs b/src/tools/miri/tests/pass-dep/libc/libc-time.rs
similarity index 97%
rename from src/tools/miri/tests/pass-dep/shims/libc-time.rs
rename to src/tools/miri/tests/pass-dep/libc/libc-time.rs
index 69c75bd..ea1e49a 100644
--- a/src/tools/miri/tests/pass-dep/shims/libc-time.rs
+++ b/src/tools/miri/tests/pass-dep/libc/libc-time.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: no libc on Windows
+//@ignore-target-windows: no libc time APIs on Windows
 //@compile-flags: -Zmiri-disable-isolation
 use std::ffi::CStr;
 use std::{env, mem, ptr};
diff --git a/src/tools/miri/tests/pass-dep/shims/mmap.rs b/src/tools/miri/tests/pass-dep/libc/mmap.rs
similarity index 98%
rename from src/tools/miri/tests/pass-dep/shims/mmap.rs
rename to src/tools/miri/tests/pass-dep/libc/mmap.rs
index 5acdedc..a0787c6 100644
--- a/src/tools/miri/tests/pass-dep/shims/mmap.rs
+++ b/src/tools/miri/tests/pass-dep/libc/mmap.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No mmap on Windows
 //@compile-flags: -Zmiri-disable-isolation -Zmiri-permissive-provenance
 #![feature(strict_provenance)]
 
diff --git a/src/tools/miri/tests/pass-dep/shims/pthread-sync.rs b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs
similarity index 99%
rename from src/tools/miri/tests/pass-dep/shims/pthread-sync.rs
rename to src/tools/miri/tests/pass-dep/libc/pthread-sync.rs
index 12d3f2b..1427526 100644
--- a/src/tools/miri/tests/pass-dep/shims/pthread-sync.rs
+++ b/src/tools/miri/tests/pass-dep/libc/pthread-sync.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 // We use `yield` to test specific interleavings, so disable automatic preemption.
 //@compile-flags: -Zmiri-preemption-rate=0
 #![feature(sync_unsafe_cell)]
diff --git a/src/tools/miri/tests/pass-dep/shims/pthread-threadname.rs b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
similarity index 97%
rename from src/tools/miri/tests/pass-dep/shims/pthread-threadname.rs
rename to src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
index bc78204..4c4f542 100644
--- a/src/tools/miri/tests/pass-dep/shims/pthread-threadname.rs
+++ b/src/tools/miri/tests/pass-dep/libc/pthread-threadname.rs
@@ -1,4 +1,4 @@
-//@ignore-target-windows: No libc on Windows
+//@ignore-target-windows: No pthreads on Windows
 use std::ffi::CStr;
 #[cfg(not(target_os = "freebsd"))]
 use std::ffi::CString;
diff --git a/src/tools/miri/tests/pass-dep/malloc.rs b/src/tools/miri/tests/pass-dep/malloc.rs
deleted file mode 100644
index 35cd137..0000000
--- a/src/tools/miri/tests/pass-dep/malloc.rs
+++ /dev/null
@@ -1,48 +0,0 @@
-//@ignore-target-windows: No libc on Windows
-
-use core::{ptr, slice};
-
-fn main() {
-    // Test that small allocations sometimes *are* not very aligned.
-    let saw_unaligned = (0..64).any(|_| unsafe {
-        let p = libc::malloc(3);
-        libc::free(p);
-        (p as usize) % 4 != 0 // find any that this is *not* 4-aligned
-    });
-    assert!(saw_unaligned);
-
-    unsafe {
-        // Use calloc for initialized memory
-        let p1 = libc::calloc(20, 1);
-
-        // old size < new size
-        let p2 = libc::realloc(p1, 40);
-        let slice = slice::from_raw_parts(p2 as *const u8, 20);
-        assert_eq!(&slice, &[0_u8; 20]);
-
-        // old size == new size
-        let p3 = libc::realloc(p2, 40);
-        let slice = slice::from_raw_parts(p3 as *const u8, 20);
-        assert_eq!(&slice, &[0_u8; 20]);
-
-        // old size > new size
-        let p4 = libc::realloc(p3, 10);
-        let slice = slice::from_raw_parts(p4 as *const u8, 10);
-        assert_eq!(&slice, &[0_u8; 10]);
-
-        libc::free(p4);
-    }
-
-    unsafe {
-        // Realloc with size 0 is okay for the null pointer
-        let p2 = libc::realloc(ptr::null_mut(), 0);
-        assert!(p2.is_null());
-    }
-
-    unsafe {
-        let p1 = libc::realloc(ptr::null_mut(), 20);
-        assert!(!p1.is_null());
-
-        libc::free(p1);
-    }
-}
diff --git a/src/tools/miri/tests/pass-dep/rand.rs b/src/tools/miri/tests/pass-dep/rand.rs
deleted file mode 100644
index 0dce6d8..0000000
--- a/src/tools/miri/tests/pass-dep/rand.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-//@compile-flags: -Zmiri-strict-provenance
-use rand::prelude::*;
-
-// Test using the `rand` crate to generate randomness.
-fn main() {
-    // Fully deterministic seeding.
-    let mut rng = SmallRng::seed_from_u64(42);
-    let _val = rng.gen::<i32>();
-    let _val = rng.gen::<isize>();
-    let _val = rng.gen::<i128>();
-
-    // Try seeding with "real" entropy.
-    let mut rng = SmallRng::from_entropy();
-    let _val = rng.gen::<i32>();
-    let _val = rng.gen::<isize>();
-    let _val = rng.gen::<i128>();
-
-    // Also try per-thread RNG.
-    let mut rng = rand::thread_rng();
-    let _val = rng.gen::<i32>();
-    let _val = rng.gen::<isize>();
-    let _val = rng.gen::<i128>();
-}
diff --git a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs b/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
deleted file mode 100644
index 9644920..0000000
--- a/src/tools/miri/tests/pass-dep/shims/libc-misc.rs
+++ /dev/null
@@ -1,242 +0,0 @@
-//@ignore-target-windows: No libc on Windows
-//@compile-flags: -Zmiri-disable-isolation
-#![feature(io_error_more)]
-#![feature(pointer_is_aligned_to)]
-#![feature(strict_provenance)]
-
-use std::mem::{self, transmute};
-use std::ptr;
-
-/// Tests whether each thread has its own `__errno_location`.
-fn test_thread_local_errno() {
-    #[cfg(any(target_os = "illumos", target_os = "solaris"))]
-    use libc::___errno as __errno_location;
-    #[cfg(target_os = "linux")]
-    use libc::__errno_location;
-    #[cfg(any(target_os = "macos", target_os = "freebsd"))]
-    use libc::__error as __errno_location;
-
-    unsafe {
-        *__errno_location() = 0xBEEF;
-        std::thread::spawn(|| {
-            assert_eq!(*__errno_location(), 0);
-            *__errno_location() = 0xBAD1DEA;
-            assert_eq!(*__errno_location(), 0xBAD1DEA);
-        })
-        .join()
-        .unwrap();
-        assert_eq!(*__errno_location(), 0xBEEF);
-    }
-}
-
-fn test_memcpy() {
-    unsafe {
-        let src = [1i8, 2, 3];
-        let dest = libc::calloc(3, 1);
-        libc::memcpy(dest, src.as_ptr() as *const libc::c_void, 3);
-        let slc = std::slice::from_raw_parts(dest as *const i8, 3);
-        assert_eq!(*slc, [1i8, 2, 3]);
-        libc::free(dest);
-    }
-
-    unsafe {
-        let src = [1i8, 2, 3];
-        let dest = libc::calloc(4, 1);
-        libc::memcpy(dest, src.as_ptr() as *const libc::c_void, 3);
-        let slc = std::slice::from_raw_parts(dest as *const i8, 4);
-        assert_eq!(*slc, [1i8, 2, 3, 0]);
-        libc::free(dest);
-    }
-
-    unsafe {
-        let src = 123_i32;
-        let mut dest = 0_i32;
-        libc::memcpy(
-            &mut dest as *mut i32 as *mut libc::c_void,
-            &src as *const i32 as *const libc::c_void,
-            mem::size_of::<i32>(),
-        );
-        assert_eq!(dest, src);
-    }
-
-    unsafe {
-        let src = Some(123);
-        let mut dest: Option<i32> = None;
-        libc::memcpy(
-            &mut dest as *mut Option<i32> as *mut libc::c_void,
-            &src as *const Option<i32> as *const libc::c_void,
-            mem::size_of::<Option<i32>>(),
-        );
-        assert_eq!(dest, src);
-    }
-
-    unsafe {
-        let src = &123;
-        let mut dest = &42;
-        libc::memcpy(
-            &mut dest as *mut &'static i32 as *mut libc::c_void,
-            &src as *const &'static i32 as *const libc::c_void,
-            mem::size_of::<&'static i32>(),
-        );
-        assert_eq!(*dest, 123);
-    }
-}
-
-fn test_strcpy() {
-    use std::ffi::{CStr, CString};
-
-    // case: src_size equals dest_size
-    unsafe {
-        let src = CString::new("rust").unwrap();
-        let size = src.as_bytes_with_nul().len();
-        let dest = libc::malloc(size);
-        libc::strcpy(dest as *mut libc::c_char, src.as_ptr());
-        assert_eq!(CStr::from_ptr(dest as *const libc::c_char), src.as_ref());
-        libc::free(dest);
-    }
-
-    // case: src_size is less than dest_size
-    unsafe {
-        let src = CString::new("rust").unwrap();
-        let size = src.as_bytes_with_nul().len();
-        let dest = libc::malloc(size + 1);
-        libc::strcpy(dest as *mut libc::c_char, src.as_ptr());
-        assert_eq!(CStr::from_ptr(dest as *const libc::c_char), src.as_ref());
-        libc::free(dest);
-    }
-}
-
-#[cfg(target_os = "linux")]
-fn test_sigrt() {
-    let min = libc::SIGRTMIN();
-    let max = libc::SIGRTMAX();
-
-    // "The Linux kernel supports a range of 33 different real-time
-    // signals, numbered 32 to 64"
-    assert!(min >= 32);
-    assert!(max >= 32);
-    assert!(min <= 64);
-    assert!(max <= 64);
-
-    // "POSIX.1-2001 requires that an implementation support at least
-    // _POSIX_RTSIG_MAX (8) real-time signals."
-    assert!(min < max);
-    assert!(max - min >= 8)
-}
-
-fn test_dlsym() {
-    let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"notasymbol\0".as_ptr().cast()) };
-    assert!(addr as usize == 0);
-
-    let addr = unsafe { libc::dlsym(libc::RTLD_DEFAULT, b"isatty\0".as_ptr().cast()) };
-    assert!(addr as usize != 0);
-    let isatty: extern "C" fn(i32) -> i32 = unsafe { transmute(addr) };
-    assert_eq!(isatty(999), 0);
-    let errno = std::io::Error::last_os_error().raw_os_error().unwrap();
-    assert_eq!(errno, libc::EBADF);
-}
-
-#[cfg(not(any(target_os = "macos", target_os = "illumos")))]
-fn test_reallocarray() {
-    unsafe {
-        let mut p = libc::reallocarray(std::ptr::null_mut(), 4096, 2);
-        assert!(!p.is_null());
-        libc::free(p);
-        p = libc::malloc(16);
-        let r = libc::reallocarray(p, 2, 32);
-        assert!(!r.is_null());
-        libc::free(r);
-    }
-}
-
-fn test_memalign() {
-    // A normal allocation.
-    unsafe {
-        let mut ptr: *mut libc::c_void = ptr::null_mut();
-        let align = 8;
-        let size = 64;
-        assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
-        assert!(!ptr.is_null());
-        assert!(ptr.is_aligned_to(align));
-        ptr.cast::<u8>().write_bytes(1, size);
-        libc::free(ptr);
-    }
-
-    // Align > size.
-    unsafe {
-        let mut ptr: *mut libc::c_void = ptr::null_mut();
-        let align = 64;
-        let size = 8;
-        assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
-        assert!(!ptr.is_null());
-        assert!(ptr.is_aligned_to(align));
-        ptr.cast::<u8>().write_bytes(1, size);
-        libc::free(ptr);
-    }
-
-    // Size not multiple of align
-    unsafe {
-        let mut ptr: *mut libc::c_void = ptr::null_mut();
-        let align = 16;
-        let size = 31;
-        assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
-        assert!(!ptr.is_null());
-        assert!(ptr.is_aligned_to(align));
-        ptr.cast::<u8>().write_bytes(1, size);
-        libc::free(ptr);
-    }
-
-    // Size == 0
-    unsafe {
-        let mut ptr: *mut libc::c_void = ptr::null_mut();
-        let align = 64;
-        let size = 0;
-        assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0);
-        // We are not required to return null if size == 0, but we currently do.
-        // It's fine to remove this assert if we start returning non-null pointers.
-        assert!(ptr.is_null());
-        assert!(ptr.is_aligned_to(align));
-        // Regardless of what we return, it must be `free`able.
-        libc::free(ptr);
-    }
-
-    // Non-power of 2 align
-    unsafe {
-        let mut ptr: *mut libc::c_void = ptr::without_provenance_mut(0x1234567);
-        let align = 15;
-        let size = 8;
-        assert_eq!(libc::posix_memalign(&mut ptr, align, size), libc::EINVAL);
-        // The pointer is not modified on failure, posix_memalign(3) says:
-        // > On Linux (and other systems), posix_memalign() does  not  modify  memptr  on failure.
-        // > A requirement standardizing this behavior was added in POSIX.1-2008 TC2.
-        assert_eq!(ptr.addr(), 0x1234567);
-    }
-
-    // Too small align (smaller than ptr)
-    unsafe {
-        let mut ptr: *mut libc::c_void = ptr::without_provenance_mut(0x1234567);
-        let align = std::mem::size_of::<usize>() / 2;
-        let size = 8;
-        assert_eq!(libc::posix_memalign(&mut ptr, align, size), libc::EINVAL);
-        // The pointer is not modified on failure, posix_memalign(3) says:
-        // > On Linux (and other systems), posix_memalign() does  not  modify  memptr  on failure.
-        // > A requirement standardizing this behavior was added in POSIX.1-2008 TC2.
-        assert_eq!(ptr.addr(), 0x1234567);
-    }
-}
-
-fn main() {
-    test_thread_local_errno();
-
-    test_dlsym();
-
-    test_memcpy();
-    test_strcpy();
-
-    test_memalign();
-    #[cfg(not(any(target_os = "macos", target_os = "illumos")))]
-    test_reallocarray();
-
-    #[cfg(target_os = "linux")]
-    test_sigrt();
-}
diff --git a/src/tools/miri/tests/pass-dep/wcslen.rs b/src/tools/miri/tests/pass-dep/wcslen.rs
new file mode 100644
index 0000000..c5c9d99
--- /dev/null
+++ b/src/tools/miri/tests/pass-dep/wcslen.rs
@@ -0,0 +1,20 @@
+fn to_c_wchar_t_str(s: &str) -> Vec<libc::wchar_t> {
+    let mut r = Vec::<libc::wchar_t>::new();
+    for c in s.bytes() {
+        if c == 0 {
+            panic!("can't contain a null character");
+        }
+        if c >= 128 {
+            panic!("only ASCII supported");
+        }
+        r.push(c.into());
+    }
+    r.push(0);
+    r
+}
+
+pub fn main() {
+    let s = to_c_wchar_t_str("Rust");
+    let len = unsafe { libc::wcslen(s.as_ptr()) };
+    assert_eq!(len, 4);
+}
diff --git a/src/tools/miri/tests/pass/align_offset_symbolic.rs b/src/tools/miri/tests/pass/align_offset_symbolic.rs
index dec3d77..9647277 100644
--- a/src/tools/miri/tests/pass/align_offset_symbolic.rs
+++ b/src/tools/miri/tests/pass/align_offset_symbolic.rs
@@ -118,10 +118,9 @@
     let parts: (*const (), *const u8) = unsafe { mem::transmute(ptr) };
     let vtable = parts.1;
     let offset = vtable.align_offset(mem::align_of::<TWOPTR>());
-    let _vtable_aligned = vtable.wrapping_add(offset) as *const [TWOPTR; 0];
-    // FIXME: we can't actually do the access since vtable pointers act like zero-sized allocations.
-    // Enable the next line once https://github.com/rust-lang/rust/issues/117945 is implemented.
-    //let _place = unsafe { &*vtable_aligned };
+    let vtable_aligned = vtable.wrapping_add(offset) as *const [TWOPTR; 0];
+    // Zero-sized deref, so no in-bounds requirement.
+    let _place = unsafe { &*vtable_aligned };
 }
 
 fn main() {
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs
index 8d3173d..3fff792 100644
--- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs
+++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v0.rs
@@ -27,7 +27,7 @@
 fn main() {
     let mut seen_main = false;
     let frames = func_a();
-    for frame in frames.into_iter() {
+    for frame in frames.iter() {
         let miri_frame = unsafe { miri_resolve_frame(*frame, 0) };
         let name = String::from_utf8(miri_frame.name.into()).unwrap();
         let filename = String::from_utf8(miri_frame.filename.into()).unwrap();
diff --git a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.rs b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.rs
index ad05271..a3060ab 100644
--- a/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.rs
+++ b/src/tools/miri/tests/pass/backtrace/backtrace-api-v1.rs
@@ -32,7 +32,7 @@
 fn main() {
     let mut seen_main = false;
     let frames = func_a();
-    for frame in frames.into_iter() {
+    for frame in frames.iter() {
         let miri_frame = unsafe { miri_resolve_frame(*frame, 1) };
 
         let mut name = vec![0; miri_frame.name_len];
diff --git a/src/tools/miri/tests/pass/empty_main.rs b/src/tools/miri/tests/pass/empty_main.rs
new file mode 100644
index 0000000..d081b6d
--- /dev/null
+++ b/src/tools/miri/tests/pass/empty_main.rs
@@ -0,0 +1,3 @@
+// This may look trivial, but a bunch of code runs in std before
+// `main` is called, so we are ensuring that that all works.
+fn main() {}
diff --git a/src/tools/miri/tests/pass/float.rs b/src/tools/miri/tests/pass/float.rs
index 1bb44d5..8aea9b3 100644
--- a/src/tools/miri/tests/pass/float.rs
+++ b/src/tools/miri/tests/pass/float.rs
@@ -1,5 +1,6 @@
 #![feature(stmt_expr_attributes)]
 #![feature(float_gamma)]
+#![feature(core_intrinsics)]
 #![allow(arithmetic_overflow)]
 
 use std::fmt::Debug;
@@ -22,6 +23,8 @@
     rounding();
     mul_add();
     libm();
+    test_fast();
+    test_algebraic();
 }
 
 // Helper function to avoid promotion so that this tests "run-time" casts, not CTFE.
@@ -751,3 +754,67 @@
     assert_approx_eq!(val, (2.0 * f64::consts::PI.sqrt()).ln());
     assert_eq!(sign, -1);
 }
+
+fn test_fast() {
+    use std::intrinsics::{fadd_fast, fdiv_fast, fmul_fast, frem_fast, fsub_fast};
+
+    #[inline(never)]
+    pub fn test_operations_f64(a: f64, b: f64) {
+        // make sure they all map to the correct operation
+        unsafe {
+            assert_eq!(fadd_fast(a, b), a + b);
+            assert_eq!(fsub_fast(a, b), a - b);
+            assert_eq!(fmul_fast(a, b), a * b);
+            assert_eq!(fdiv_fast(a, b), a / b);
+            assert_eq!(frem_fast(a, b), a % b);
+        }
+    }
+
+    #[inline(never)]
+    pub fn test_operations_f32(a: f32, b: f32) {
+        // make sure they all map to the correct operation
+        unsafe {
+            assert_eq!(fadd_fast(a, b), a + b);
+            assert_eq!(fsub_fast(a, b), a - b);
+            assert_eq!(fmul_fast(a, b), a * b);
+            assert_eq!(fdiv_fast(a, b), a / b);
+            assert_eq!(frem_fast(a, b), a % b);
+        }
+    }
+
+    test_operations_f64(1., 2.);
+    test_operations_f64(10., 5.);
+    test_operations_f32(11., 2.);
+    test_operations_f32(10., 15.);
+}
+
+fn test_algebraic() {
+    use std::intrinsics::{
+        fadd_algebraic, fdiv_algebraic, fmul_algebraic, frem_algebraic, fsub_algebraic,
+    };
+
+    #[inline(never)]
+    pub fn test_operations_f64(a: f64, b: f64) {
+        // make sure they all map to the correct operation
+        assert_eq!(fadd_algebraic(a, b), a + b);
+        assert_eq!(fsub_algebraic(a, b), a - b);
+        assert_eq!(fmul_algebraic(a, b), a * b);
+        assert_eq!(fdiv_algebraic(a, b), a / b);
+        assert_eq!(frem_algebraic(a, b), a % b);
+    }
+
+    #[inline(never)]
+    pub fn test_operations_f32(a: f32, b: f32) {
+        // make sure they all map to the correct operation
+        assert_eq!(fadd_algebraic(a, b), a + b);
+        assert_eq!(fsub_algebraic(a, b), a - b);
+        assert_eq!(fmul_algebraic(a, b), a * b);
+        assert_eq!(fdiv_algebraic(a, b), a / b);
+        assert_eq!(frem_algebraic(a, b), a % b);
+    }
+
+    test_operations_f64(1., 2.);
+    test_operations_f64(10., 5.);
+    test_operations_f32(11., 2.);
+    test_operations_f32(10., 15.);
+}
diff --git a/src/tools/miri/tests/pass/float_fast_math.rs b/src/tools/miri/tests/pass/float_fast_math.rs
deleted file mode 100644
index 52d9856..0000000
--- a/src/tools/miri/tests/pass/float_fast_math.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-#![feature(core_intrinsics)]
-
-use std::intrinsics::{fadd_fast, fdiv_fast, fmul_fast, frem_fast, fsub_fast};
-
-#[inline(never)]
-pub fn test_operations_f64(a: f64, b: f64) {
-    // make sure they all map to the correct operation
-    unsafe {
-        assert_eq!(fadd_fast(a, b), a + b);
-        assert_eq!(fsub_fast(a, b), a - b);
-        assert_eq!(fmul_fast(a, b), a * b);
-        assert_eq!(fdiv_fast(a, b), a / b);
-        assert_eq!(frem_fast(a, b), a % b);
-    }
-}
-
-#[inline(never)]
-pub fn test_operations_f32(a: f32, b: f32) {
-    // make sure they all map to the correct operation
-    unsafe {
-        assert_eq!(fadd_fast(a, b), a + b);
-        assert_eq!(fsub_fast(a, b), a - b);
-        assert_eq!(fmul_fast(a, b), a * b);
-        assert_eq!(fdiv_fast(a, b), a / b);
-        assert_eq!(frem_fast(a, b), a % b);
-    }
-}
-
-fn main() {
-    test_operations_f64(1., 2.);
-    test_operations_f64(10., 5.);
-    test_operations_f32(11., 2.);
-    test_operations_f32(10., 15.);
-}
diff --git a/src/tools/miri/tests/pass/function_calls/abi_compat.rs b/src/tools/miri/tests/pass/function_calls/abi_compat.rs
index 14fd2d3..136660a 100644
--- a/src/tools/miri/tests/pass/function_calls/abi_compat.rs
+++ b/src/tools/miri/tests/pass/function_calls/abi_compat.rs
@@ -70,7 +70,7 @@
         test_abi_compat(0usize, 0u64);
         test_abi_compat(0isize, 0i64);
     }
-    test_abi_compat(42u32, num::NonZeroU32::new(1).unwrap());
+    test_abi_compat(42u32, num::NonZero::new(1u32).unwrap());
     // - `char` and `u32`.
     test_abi_compat(42u32, 'x');
     // - Reference/pointer types with the same pointee.
@@ -86,9 +86,9 @@
     // - Guaranteed null-pointer-optimizations (RFC 3391).
     test_abi_compat(&0u32 as *const u32, Some(&0u32));
     test_abi_compat(main as fn(), Some(main as fn()));
-    test_abi_compat(0u32, Some(num::NonZeroU32::new(1).unwrap()));
+    test_abi_compat(0u32, Some(num::NonZero::new(1u32).unwrap()));
     test_abi_compat(&0u32 as *const u32, Some(Wrapper(&0u32)));
-    test_abi_compat(0u32, Some(Wrapper(num::NonZeroU32::new(1).unwrap())));
+    test_abi_compat(0u32, Some(Wrapper(num::NonZero::new(1u32).unwrap())));
 
     // These must work for *any* type, since we guarantee that `repr(transparent)` is ABI-compatible
     // with the wrapped field.
@@ -102,7 +102,7 @@
     test_abi_newtype::<[u32; 2]>();
     test_abi_newtype::<[u32; 32]>();
     test_abi_newtype::<Option<i32>>();
-    test_abi_newtype::<Option<num::NonZeroU32>>();
+    test_abi_newtype::<Option<num::NonZero<u32>>>();
 
     // Extra test for assumptions made by arbitrary-self-dyn-receivers.
     // This is interesting since these types are not `repr(transparent)`. So this is not part of our
diff --git a/src/tools/miri/tests/pass/integer-ops.rs b/src/tools/miri/tests/pass/integer-ops.rs
index 0ec1f8e..3f8ac34 100644
--- a/src/tools/miri/tests/pass/integer-ops.rs
+++ b/src/tools/miri/tests/pass/integer-ops.rs
@@ -1,7 +1,64 @@
 //@compile-flags: -Coverflow-checks=off
 #![allow(arithmetic_overflow)]
 
+fn basic() {
+    fn ret() -> i64 {
+        1
+    }
+
+    fn neg() -> i64 {
+        -1
+    }
+
+    fn add() -> i64 {
+        1 + 2
+    }
+
+    fn indirect_add() -> i64 {
+        let x = 1;
+        let y = 2;
+        x + y
+    }
+
+    fn arith() -> i32 {
+        3 * 3 + 4 * 4
+    }
+
+    fn match_int() -> i16 {
+        let n = 2;
+        match n {
+            0 => 0,
+            1 => 10,
+            2 => 20,
+            3 => 30,
+            _ => 100,
+        }
+    }
+
+    fn match_int_range() -> i64 {
+        let n = 42;
+        match n {
+            0..=9 => 0,
+            10..=19 => 1,
+            20..=29 => 2,
+            30..=39 => 3,
+            40..=42 => 4,
+            _ => 5,
+        }
+    }
+
+    assert_eq!(ret(), 1);
+    assert_eq!(neg(), -1);
+    assert_eq!(add(), 3);
+    assert_eq!(indirect_add(), 3);
+    assert_eq!(arith(), 5 * 5);
+    assert_eq!(match_int(), 20);
+    assert_eq!(match_int_range(), 4);
+}
+
 pub fn main() {
+    basic();
+
     // This tests that we do (not) do sign extension properly when loading integers
     assert_eq!(u32::MAX as i64, 4294967295);
     assert_eq!(i32::MIN as i64, -2147483648);
@@ -152,6 +209,10 @@
 
     assert_eq!(5i32.overflowing_mul(2), (10, false));
     assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));
+    assert_eq!(i64::MIN.overflowing_mul(-1), (i64::MIN, true));
+    assert_eq!(i32::MIN.overflowing_mul(-1), (i32::MIN, true));
+    assert_eq!(i16::MIN.overflowing_mul(-1), (i16::MIN, true));
+    assert_eq!(i8::MIN.overflowing_mul(-1), (i8::MIN, true));
 
     assert_eq!(5i32.overflowing_div(2), (2, false));
     assert_eq!(i32::MIN.overflowing_div(-1), (i32::MIN, true));
diff --git a/src/tools/miri/tests/pass/integers.rs b/src/tools/miri/tests/pass/integers.rs
deleted file mode 100644
index c04c692..0000000
--- a/src/tools/miri/tests/pass/integers.rs
+++ /dev/null
@@ -1,58 +0,0 @@
-fn ret() -> i64 {
-    1
-}
-
-fn neg() -> i64 {
-    -1
-}
-
-fn add() -> i64 {
-    1 + 2
-}
-
-fn indirect_add() -> i64 {
-    let x = 1;
-    let y = 2;
-    x + y
-}
-
-fn arith() -> i32 {
-    3 * 3 + 4 * 4
-}
-
-fn match_int() -> i16 {
-    let n = 2;
-    match n {
-        0 => 0,
-        1 => 10,
-        2 => 20,
-        3 => 30,
-        _ => 100,
-    }
-}
-
-fn match_int_range() -> i64 {
-    let n = 42;
-    match n {
-        0..=9 => 0,
-        10..=19 => 1,
-        20..=29 => 2,
-        30..=39 => 3,
-        40..=42 => 4,
-        _ => 5,
-    }
-}
-
-fn main() {
-    assert_eq!(ret(), 1);
-    assert_eq!(neg(), -1);
-    assert_eq!(add(), 3);
-    assert_eq!(indirect_add(), 3);
-    assert_eq!(arith(), 5 * 5);
-    assert_eq!(match_int(), 20);
-    assert_eq!(match_int_range(), 4);
-    assert_eq!(i64::MIN.overflowing_mul(-1), (i64::MIN, true));
-    assert_eq!(i32::MIN.overflowing_mul(-1), (i32::MIN, true));
-    assert_eq!(i16::MIN.overflowing_mul(-1), (i16::MIN, true));
-    assert_eq!(i8::MIN.overflowing_mul(-1), (i8::MIN, true));
-}
diff --git a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
index 1fc713d..248a57d 100644
--- a/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
+++ b/src/tools/miri/tests/pass/intrinsics/portable-simd.rs
@@ -506,6 +506,21 @@
         assert!(!simd_reduce_all(i32x2::from_array([0, -1])));
 
         assert_eq!(
+            simd_ctlz(i32x4::from_array([0, i32::MAX, i32::MIN, -1_i32])),
+            i32x4::from_array([32, 1, 0, 0])
+        );
+
+        assert_eq!(
+            simd_ctpop(i32x4::from_array([0, i32::MAX, i32::MIN, -1_i32])),
+            i32x4::from_array([0, 31, 1, 32])
+        );
+
+        assert_eq!(
+            simd_cttz(i32x4::from_array([0, i32::MAX, i32::MIN, -1_i32])),
+            i32x4::from_array([32, 0, 31, 0])
+        );
+
+        assert_eq!(
             simd_select(i8x4::from_array([0, -1, -1, 0]), a, b),
             i32x4::from_array([1, 10, 10, 4])
         );
diff --git a/src/tools/miri/tests/pass/panic/unwind_dwarf.rs b/src/tools/miri/tests/pass/panic/unwind_dwarf.rs
new file mode 100644
index 0000000..f690be4
--- /dev/null
+++ b/src/tools/miri/tests/pass/panic/unwind_dwarf.rs
@@ -0,0 +1,96 @@
+//@ignore-target-windows: Windows uses a different unwinding mechanism
+#![feature(core_intrinsics, panic_unwind, rustc_attrs)]
+#![allow(internal_features)]
+
+//! Unwinding using `_Unwind_RaiseException`
+
+extern crate unwind as uw;
+
+use std::any::Any;
+use std::ptr;
+
+#[repr(C)]
+struct Exception {
+    _uwe: uw::_Unwind_Exception,
+    cause: Box<dyn Any + Send>,
+}
+
+pub fn panic(data: Box<dyn Any + Send>) -> u32 {
+    extern "C" fn exception_cleanup(
+        _unwind_code: uw::_Unwind_Reason_Code,
+        _exception: *mut uw::_Unwind_Exception,
+    ) {
+        std::process::abort();
+    }
+
+    let exception = Box::new(Exception {
+        _uwe: uw::_Unwind_Exception {
+            exception_class: miri_exception_class(),
+            exception_cleanup: Some(exception_cleanup),
+            private: [core::ptr::null(); uw::unwinder_private_data_size],
+        },
+        cause: data,
+    });
+    let exception_param = Box::into_raw(exception) as *mut uw::_Unwind_Exception;
+    return unsafe { uw::_Unwind_RaiseException(exception_param) as u32 };
+}
+
+pub unsafe fn rust_panic_cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
+    let exception = ptr as *mut uw::_Unwind_Exception;
+    if (*exception).exception_class != miri_exception_class() {
+        std::process::abort();
+    }
+
+    let exception = exception.cast::<Exception>();
+
+    let exception = Box::from_raw(exception as *mut Exception);
+    exception.cause
+}
+
+fn miri_exception_class() -> uw::_Unwind_Exception_Class {
+    // M O Z \0  M I R I -- vendor, language
+    // (Miri's own exception class is just used for testing)
+    0x4d4f5a_00_4d495249
+}
+
+pub fn catch_unwind<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>> {
+    struct Data<F, R> {
+        f: Option<F>,
+        r: Option<R>,
+        p: Option<Box<dyn Any + Send>>,
+    }
+
+    let mut data = Data { f: Some(f), r: None, p: None };
+
+    let data_ptr = ptr::addr_of_mut!(data) as *mut u8;
+    unsafe {
+        return if std::intrinsics::catch_unwind(do_call::<F, R>, data_ptr, do_catch::<F, R>) == 0 {
+            Ok(data.r.take().unwrap())
+        } else {
+            Err(data.p.take().unwrap())
+        };
+    }
+
+    fn do_call<F: FnOnce() -> R, R>(data: *mut u8) {
+        unsafe {
+            let data = &mut *data.cast::<Data<F, R>>();
+            let f = data.f.take().unwrap();
+            data.r = Some(f());
+        }
+    }
+
+    #[rustc_nounwind]
+    fn do_catch<F: FnOnce() -> R, R>(data: *mut u8, payload: *mut u8) {
+        unsafe {
+            let obj = rust_panic_cleanup(payload);
+            (*data.cast::<Data<F, R>>()).p = Some(obj);
+        }
+    }
+}
+
+fn main() {
+    assert_eq!(
+        catch_unwind(|| panic(Box::new(42))).unwrap_err().downcast::<i32>().unwrap(),
+        Box::new(42)
+    );
+}
diff --git a/src/tools/miri/tests/pass/shims/available-parallelism-miri-num-cpus.rs b/src/tools/miri/tests/pass/shims/available-parallelism-miri-num-cpus.rs
index 137fa51..0d96bc2 100644
--- a/src/tools/miri/tests/pass/shims/available-parallelism-miri-num-cpus.rs
+++ b/src/tools/miri/tests/pass/shims/available-parallelism-miri-num-cpus.rs
@@ -1,8 +1,8 @@
 //@compile-flags: -Zmiri-num-cpus=1024
 
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 use std::thread::available_parallelism;
 
 fn main() {
-    assert_eq!(available_parallelism().unwrap(), NonZeroUsize::new(1024).unwrap());
+    assert_eq!(available_parallelism().unwrap(), NonZero::new(1024).unwrap());
 }
diff --git a/src/tools/miri/tests/pass/shims/env/home.rs b/src/tools/miri/tests/pass/shims/env/home.rs
index c237f9e..8b4b907 100644
--- a/src/tools/miri/tests/pass/shims/env/home.rs
+++ b/src/tools/miri/tests/pass/shims/env/home.rs
@@ -2,8 +2,12 @@
 use std::env;
 
 fn main() {
-    env::remove_var("HOME"); // make sure we enter the interesting codepath
-    env::remove_var("USERPROFILE"); // Windows also looks as this env var
+    // Remove the env vars to hit the underlying shim -- except
+    // on android where the env var is all we have.
+    #[cfg(not(target_os = "android"))]
+    env::remove_var("HOME");
+    env::remove_var("USERPROFILE");
+
     #[allow(deprecated)]
     env::home_dir().unwrap();
 }
diff --git a/src/tools/miri/tests/pass/shims/fs-symlink.rs b/src/tools/miri/tests/pass/shims/fs-symlink.rs
new file mode 100644
index 0000000..4d5103b
--- /dev/null
+++ b/src/tools/miri/tests/pass/shims/fs-symlink.rs
@@ -0,0 +1,50 @@
+// Symlink tests are separate since they don't in general work on a Windows host.
+//@ignore-host-windows: creating symlinks requires admin permissions on Windows
+//@ignore-target-windows: File handling is not implemented yet
+//@compile-flags: -Zmiri-disable-isolation
+
+use std::fs::{read_link, remove_file, File};
+use std::io::{Read, Result};
+use std::path::Path;
+
+#[path = "../../utils/mod.rs"]
+mod utils;
+
+fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> {
+    // Test that the file metadata is correct.
+    let metadata = path.metadata()?;
+    // `path` should point to a file.
+    assert!(metadata.is_file());
+    // The size of the file must be equal to the number of written bytes.
+    assert_eq!(bytes.len() as u64, metadata.len());
+    Ok(())
+}
+
+fn main() {
+    let bytes = b"Hello, World!\n";
+    let path = utils::prepare_with_content("miri_test_fs_link_target.txt", bytes);
+    let symlink_path = utils::prepare("miri_test_fs_symlink.txt");
+
+    // Creating a symbolic link should succeed.
+    #[cfg(unix)]
+    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
+    #[cfg(windows)]
+    std::os::windows::fs::symlink_file(&path, &symlink_path).unwrap();
+    // Test that the symbolic link has the same contents as the file.
+    let mut symlink_file = File::open(&symlink_path).unwrap();
+    let mut contents = Vec::new();
+    symlink_file.read_to_end(&mut contents).unwrap();
+    assert_eq!(bytes, contents.as_slice());
+
+    // Test that metadata of a symbolic link (i.e., the file it points to) is correct.
+    check_metadata(bytes, &symlink_path).unwrap();
+    // Test that the metadata of a symbolic link is correct when not following it.
+    assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
+    // Check that we can follow the link.
+    assert_eq!(read_link(&symlink_path).unwrap(), path);
+    // Removing symbolic link should succeed.
+    remove_file(&symlink_path).unwrap();
+
+    // Removing file should succeed.
+    remove_file(&path).unwrap();
+}
diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs
index 8a500b8..35980fa 100644
--- a/src/tools/miri/tests/pass/shims/fs.rs
+++ b/src/tools/miri/tests/pass/shims/fs.rs
@@ -1,21 +1,17 @@
 //@ignore-target-windows: File handling is not implemented yet
 //@compile-flags: -Zmiri-disable-isolation
 
-// If this test is failing for you locally, you can try
-// 1. Deleting the files `/tmp/miri_*`
-// 2. Setting `MIRI_TEMP` or `TMPDIR` to a different directory, without the `miri_*` files
-
 #![feature(io_error_more)]
 #![feature(io_error_uncategorized)]
 
 use std::collections::HashMap;
 use std::ffi::OsString;
 use std::fs::{
-    canonicalize, create_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, rename,
-    File, OpenOptions,
+    canonicalize, create_dir, read_dir, remove_dir, remove_dir_all, remove_file, rename, File,
+    OpenOptions,
 };
 use std::io::{Error, ErrorKind, IsTerminal, Read, Result, Seek, SeekFrom, Write};
-use std::path::{Path, PathBuf};
+use std::path::Path;
 
 #[path = "../../utils/mod.rs"]
 mod utils;
@@ -29,7 +25,6 @@
     test_metadata();
     test_file_set_len();
     test_file_sync();
-    test_symlink();
     test_errors();
     test_rename();
     test_directory();
@@ -37,30 +32,6 @@
     test_from_raw_os_error();
 }
 
-/// Prepare: compute filename and make sure the file does not exist.
-fn prepare(filename: &str) -> PathBuf {
-    let path = utils::tmp().join(filename);
-    // Clean the paths for robustness.
-    remove_file(&path).ok();
-    path
-}
-
-/// Prepare directory: compute directory name and make sure it does not exist.
-fn prepare_dir(dirname: &str) -> PathBuf {
-    let path = utils::tmp().join(&dirname);
-    // Clean the directory for robustness.
-    remove_dir_all(&path).ok();
-    path
-}
-
-/// Prepare like above, and also write some initial content to the file.
-fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf {
-    let path = prepare(filename);
-    let mut file = File::create(&path).unwrap();
-    file.write(content).unwrap();
-    path
-}
-
 fn test_path_conversion() {
     let tmp = utils::tmp();
     assert!(tmp.is_absolute(), "{:?} is not absolute", tmp);
@@ -69,7 +40,7 @@
 
 fn test_file() {
     let bytes = b"Hello, World!\n";
-    let path = prepare("miri_test_fs_file.txt");
+    let path = utils::prepare("miri_test_fs_file.txt");
 
     // Test creating, writing and closing a file (closing is tested when `file` is dropped).
     let mut file = File::create(&path).unwrap();
@@ -96,7 +67,7 @@
 
 fn test_file_clone() {
     let bytes = b"Hello, World!\n";
-    let path = prepare_with_content("miri_test_fs_file_clone.txt", bytes);
+    let path = utils::prepare_with_content("miri_test_fs_file_clone.txt", bytes);
 
     // Cloning a file should be successful.
     let file = File::open(&path).unwrap();
@@ -111,7 +82,7 @@
 }
 
 fn test_file_create_new() {
-    let path = prepare("miri_test_fs_file_create_new.txt");
+    let path = utils::prepare("miri_test_fs_file_create_new.txt");
 
     // Creating a new file that doesn't yet exist should succeed.
     OpenOptions::new().write(true).create_new(true).open(&path).unwrap();
@@ -129,7 +100,7 @@
 
 fn test_seek() {
     let bytes = b"Hello, entire World!\n";
-    let path = prepare_with_content("miri_test_fs_seek.txt", bytes);
+    let path = utils::prepare_with_content("miri_test_fs_seek.txt", bytes);
 
     let mut file = File::open(&path).unwrap();
     let mut contents = Vec::new();
@@ -168,7 +139,7 @@
 
 fn test_metadata() {
     let bytes = b"Hello, meta-World!\n";
-    let path = prepare_with_content("miri_test_fs_metadata.txt", bytes);
+    let path = utils::prepare_with_content("miri_test_fs_metadata.txt", bytes);
 
     // Test that metadata of an absolute path is correct.
     check_metadata(bytes, &path).unwrap();
@@ -182,7 +153,7 @@
 
 fn test_file_set_len() {
     let bytes = b"Hello, World!\n";
-    let path = prepare_with_content("miri_test_fs_set_len.txt", bytes);
+    let path = utils::prepare_with_content("miri_test_fs_set_len.txt", bytes);
 
     // Test extending the file
     let mut file = OpenOptions::new().read(true).write(true).open(&path).unwrap();
@@ -208,7 +179,7 @@
 
 fn test_file_sync() {
     let bytes = b"Hello, World!\n";
-    let path = prepare_with_content("miri_test_fs_sync.txt", bytes);
+    let path = utils::prepare_with_content("miri_test_fs_sync.txt", bytes);
 
     // Test that we can call sync_data and sync_all (can't readily test effects of this operation)
     let file = OpenOptions::new().write(true).open(&path).unwrap();
@@ -223,38 +194,9 @@
     remove_file(&path).unwrap();
 }
 
-fn test_symlink() {
-    let bytes = b"Hello, World!\n";
-    let path = prepare_with_content("miri_test_fs_link_target.txt", bytes);
-    let symlink_path = prepare("miri_test_fs_symlink.txt");
-
-    // Creating a symbolic link should succeed.
-    #[cfg(unix)]
-    std::os::unix::fs::symlink(&path, &symlink_path).unwrap();
-    #[cfg(windows)]
-    std::os::windows::fs::symlink_file(&path, &symlink_path).unwrap();
-    // Test that the symbolic link has the same contents as the file.
-    let mut symlink_file = File::open(&symlink_path).unwrap();
-    let mut contents = Vec::new();
-    symlink_file.read_to_end(&mut contents).unwrap();
-    assert_eq!(bytes, contents.as_slice());
-
-    // Test that metadata of a symbolic link (i.e., the file it points to) is correct.
-    check_metadata(bytes, &symlink_path).unwrap();
-    // Test that the metadata of a symbolic link is correct when not following it.
-    assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink());
-    // Check that we can follow the link.
-    assert_eq!(read_link(&symlink_path).unwrap(), path);
-    // Removing symbolic link should succeed.
-    remove_file(&symlink_path).unwrap();
-
-    // Removing file should succeed.
-    remove_file(&path).unwrap();
-}
-
 fn test_errors() {
     let bytes = b"Hello, World!\n";
-    let path = prepare("miri_test_fs_errors.txt");
+    let path = utils::prepare("miri_test_fs_errors.txt");
 
     // The following tests also check that the `__errno_location()` shim is working properly.
     // Opening a non-existing file should fail with a "not found" error.
@@ -269,8 +211,8 @@
 
 fn test_rename() {
     // Renaming a file should succeed.
-    let path1 = prepare("miri_test_fs_rename_source.txt");
-    let path2 = prepare("miri_test_fs_rename_destination.txt");
+    let path1 = utils::prepare("miri_test_fs_rename_source.txt");
+    let path2 = utils::prepare("miri_test_fs_rename_destination.txt");
 
     let file = File::create(&path1).unwrap();
     drop(file);
@@ -289,7 +231,7 @@
 }
 
 fn test_canonicalize() {
-    let dir_path = prepare_dir("miri_test_fs_dir");
+    let dir_path = utils::prepare_dir("miri_test_fs_dir");
     create_dir(&dir_path).unwrap();
     let path = dir_path.join("test_file");
     drop(File::create(&path).unwrap());
@@ -301,7 +243,7 @@
 }
 
 fn test_directory() {
-    let dir_path = prepare_dir("miri_test_fs_dir");
+    let dir_path = utils::prepare_dir("miri_test_fs_dir");
     // Creating a directory should succeed.
     create_dir(&dir_path).unwrap();
     // Test that the metadata of a directory is correct.
diff --git a/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs b/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs
new file mode 100644
index 0000000..2d142be
--- /dev/null
+++ b/src/tools/miri/tests/pass/zero-sized-accesses-and-offsets.rs
@@ -0,0 +1,59 @@
+//! Tests specific for <https://github.com/rust-lang/rust/issues/117945>: zero-sized operations.
+#![feature(strict_provenance)]
+
+use std::ptr;
+
+fn main() {
+    // Null.
+    test_ptr(ptr::null_mut::<()>());
+    // No provenance.
+    test_ptr(ptr::without_provenance_mut::<()>(1));
+    // Out-of-bounds.
+    let mut b = Box::new(0i32);
+    let ptr = ptr::addr_of_mut!(*b) as *mut ();
+    test_ptr(ptr.wrapping_byte_add(2));
+    // Dangling (use-after-free).
+    drop(b);
+    test_ptr(ptr);
+}
+
+fn test_ptr(ptr: *mut ()) {
+    unsafe {
+        // Reads and writes.
+        let mut val = *ptr;
+        *ptr = val;
+        ptr.read();
+        ptr.write(());
+        // Memory access intrinsics.
+        // - memcpy (1st and 2nd argument)
+        ptr.copy_from_nonoverlapping(&(), 1);
+        ptr.copy_to_nonoverlapping(&mut val, 1);
+        // - memmove (1st and 2nd argument)
+        ptr.copy_from(&(), 1);
+        ptr.copy_to(&mut val, 1);
+        // - memset
+        ptr.write_bytes(0u8, 1);
+        // Offset.
+        let _ = ptr.offset(0);
+        let _ = ptr.offset(1); // this is still 0 bytes
+        // Distance.
+        let ptr = ptr.cast::<i32>();
+        ptr.offset_from(ptr);
+        /*
+        FIXME: this is disabled for now as these cases are not yet allowed.
+        // Distance from other "bad" pointers that have the same address, but different provenance. Some
+        // of this is library UB, but we don't want it to be language UB since that would violate
+        // provenance monotonicity: if we allow computing the distance between two ptrs with no
+        // provenance, we have to allow computing it between two ptrs with arbitrary provenance.
+        // - Distance from "no provenance"
+        ptr.offset_from(ptr::without_provenance_mut(ptr.addr()));
+        // - Distance from out-of-bounds pointer
+        let mut b = Box::new(0i32);
+        let other_ptr = ptr::addr_of_mut!(*b);
+        ptr.offset_from(other_ptr.with_addr(ptr.addr()));
+        // - Distance from use-after-free pointer
+        drop(b);
+        ptr.offset_from(other_ptr.with_addr(ptr.addr()));
+        */
+    }
+}
diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs
index efeefbe..3a8b098 100644
--- a/src/tools/miri/tests/ui.rs
+++ b/src/tools/miri/tests/ui.rs
@@ -1,5 +1,5 @@
 use std::ffi::OsString;
-use std::num::NonZeroUsize;
+use std::num::NonZero;
 use std::path::{Path, PathBuf};
 use std::sync::OnceLock;
 use std::{env, process::Command};
@@ -27,11 +27,12 @@
     flags.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string).collect()
 }
 
-// Build the shared object file for testing external C function calls.
-fn build_so_for_c_ffi_tests() -> PathBuf {
+// Build the shared object file for testing native function calls.
+fn build_native_lib() -> PathBuf {
     let cc = option_env!("CC").unwrap_or("cc");
     // Target directory that we can write to.
-    let so_target_dir = Path::new(&env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri-extern-so");
+    let so_target_dir =
+        Path::new(&env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri-native-lib");
     // Create the directory if it does not already exist.
     std::fs::create_dir_all(&so_target_dir)
         .expect("Failed to create directory for shared object file");
@@ -41,18 +42,18 @@
             "-shared",
             "-o",
             so_file_path.to_str().unwrap(),
-            "tests/extern-so/test.c",
+            "tests/native-lib/test.c",
             // Only add the functions specified in libcode.version to the shared object file.
             // This is to avoid automatically adding `malloc`, etc.
             // Source: https://anadoxin.org/blog/control-over-symbol-exports-in-gcc.html/
             "-fPIC",
-            "-Wl,--version-script=tests/extern-so/libtest.map",
+            "-Wl,--version-script=tests/native-lib/libtest.map",
         ])
         .output()
-        .expect("failed to generate shared object file for testing external C function calls");
+        .expect("failed to generate shared object file for testing native function calls");
     if !cc_output.status.success() {
         panic!(
-            "error in generating shared object file for testing external C function calls:\n{}",
+            "error generating shared object file for testing native function calls:\n{}",
             String::from_utf8_lossy(&cc_output.stderr),
         );
     }
@@ -76,7 +77,7 @@
         edition: Some("2021".into()), // keep in sync with `./miri run`
         threads: std::env::var("MIRI_TEST_THREADS")
             .ok()
-            .map(|threads| NonZeroUsize::new(threads.parse().unwrap()).unwrap()),
+            .map(|threads| NonZero::new(threads.parse().unwrap()).unwrap()),
         ..Config::rustc(path)
     };
 
@@ -132,13 +133,12 @@
     config.program.args.push("--target".into());
     config.program.args.push(target.into());
 
-    // If we're testing the extern-so functionality, then build the shared object file for testing
+    // If we're testing the native-lib functionality, then build the shared object file for testing
     // external C function calls and push the relevant compiler flag.
-    if path.starts_with("tests/extern-so/") {
-        assert!(cfg!(target_os = "linux"));
-        let so_file_path = build_so_for_c_ffi_tests();
-        let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file=");
-        flag.push(so_file_path.into_os_string());
+    if path.starts_with("tests/native-lib/") {
+        let native_lib = build_native_lib();
+        let mut flag = std::ffi::OsString::from("-Zmiri-native-lib=");
+        flag.push(native_lib.into_os_string());
         config.program.args.push(flag);
     }
 
@@ -292,10 +292,10 @@
         tmpdir.path(),
     )?;
     if cfg!(target_os = "linux") {
-        ui(Mode::Pass, "tests/extern-so/pass", &target, WithoutDependencies, tmpdir.path())?;
+        ui(Mode::Pass, "tests/native-lib/pass", &target, WithoutDependencies, tmpdir.path())?;
         ui(
             Mode::Fail { require_patterns: true, rustfix: RustfixMode::Disabled },
-            "tests/extern-so/fail",
+            "tests/native-lib/fail",
             &target,
             WithoutDependencies,
             tmpdir.path(),
diff --git a/src/tools/miri/tests/utils/fs.rs b/src/tools/miri/tests/utils/fs.rs
index 0242a22..7340908 100644
--- a/src/tools/miri/tests/utils/fs.rs
+++ b/src/tools/miri/tests/utils/fs.rs
@@ -1,4 +1,5 @@
 use std::ffi::OsString;
+use std::fs;
 use std::path::PathBuf;
 
 use super::miri_extern;
@@ -27,3 +28,26 @@
     // These are host paths. We need to convert them to the target.
     host_to_target_path(path)
 }
+
+/// Prepare: compute filename and make sure the file does not exist.
+pub fn prepare(filename: &str) -> PathBuf {
+    let path = tmp().join(filename);
+    // Clean the paths for robustness.
+    fs::remove_file(&path).ok();
+    path
+}
+
+/// Prepare like above, and also write some initial content to the file.
+pub fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf {
+    let path = prepare(filename);
+    fs::write(&path, content).unwrap();
+    path
+}
+
+/// Prepare directory: compute directory name and make sure it does not exist.
+pub fn prepare_dir(dirname: &str) -> PathBuf {
+    let path = tmp().join(&dirname);
+    // Clean the directory for robustness.
+    fs::remove_dir_all(&path).ok();
+    path
+}
diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml
index 4cb6acb..88e8640 100644
--- a/src/tools/opt-dist/Cargo.toml
+++ b/src/tools/opt-dist/Cargo.toml
@@ -13,10 +13,8 @@
 sysinfo = { version = "0.30", default-features = false }
 fs_extra = "1"
 camino = "1"
-reqwest = { version = "0.11", features = ["blocking"] }
-zip = { version = "0.6", default-features = false, features = ["deflate"] }
 tar = "0.4"
-xz = "0.1"
+xz = { version = "0.1", package = "xz2" }
 serde = { version = "1", features = ["derive"] }
 serde_json = "1"
 glob = "0.3"
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index ffb0121..a709076 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -3,10 +3,7 @@
 use camino::{Utf8Path, Utf8PathBuf};
 use clap::Parser;
 use log::LevelFilter;
-use std::io::Cursor;
-use std::time::Duration;
 use utils::io;
-use zip::ZipArchive;
 
 use crate::environment::{Environment, EnvironmentBuilder};
 use crate::exec::{cmd, Bootstrap};
@@ -17,9 +14,9 @@
     rustc_benchmarks,
 };
 use crate::utils::artifact_size::print_binary_sizes;
-use crate::utils::io::{copy_directory, move_directory, reset_directory};
+use crate::utils::io::{copy_directory, reset_directory};
 use crate::utils::{
-    clear_llvm_files, format_env_variables, print_free_disk_space, retry_action, with_log_group,
+    clear_llvm_files, format_env_variables, print_free_disk_space, with_log_group,
     write_timer_to_summary,
 };
 
@@ -69,6 +66,15 @@
         #[arg(long, default_value = "opt-artifacts")]
         artifact_dir: Utf8PathBuf,
 
+        /// Checkout directory of `rustc-perf`.
+        ///
+        /// If unspecified, defaults to the rustc-perf submodule in the rustc checkout dir
+        /// (`src/tools/rustc-perf`), which should have been initialized when building this tool.
+        // FIXME: Move update_submodule into build_helper, that way we can also ensure the submodule
+        // is updated when _running_ opt-dist, rather than building.
+        #[arg(long)]
+        rustc_perf_checkout_dir: Option<Utf8PathBuf>,
+
         /// Is LLVM for `rustc` built in shared library mode?
         #[arg(long, default_value_t = true)]
         llvm_shared: bool,
@@ -109,6 +115,7 @@
             llvm_dir,
             python,
             artifact_dir,
+            rustc_perf_checkout_dir,
             llvm_shared,
             use_bolt,
             skipped_tests,
@@ -121,6 +128,7 @@
                 .host_llvm_dir(llvm_dir)
                 .artifact_dir(artifact_dir)
                 .build_dir(checkout_dir)
+                .prebuilt_rustc_perf(rustc_perf_checkout_dir)
                 .shared_llvm(llvm_shared)
                 .use_bolt(use_bolt)
                 .skipped_tests(skipped_tests)
@@ -140,8 +148,6 @@
                 .host_llvm_dir(Utf8PathBuf::from("/rustroot"))
                 .artifact_dir(Utf8PathBuf::from("/tmp/tmp-multistage/opt-artifacts"))
                 .build_dir(checkout_dir.join("obj"))
-                // /tmp/rustc-perf comes from the x64 dist Dockerfile
-                .prebuilt_rustc_perf(Some(Utf8PathBuf::from("/tmp/rustc-perf")))
                 .shared_llvm(true)
                 .use_bolt(true)
                 .skipped_tests(vec![
@@ -185,9 +191,12 @@
 ) -> anyhow::Result<()> {
     reset_directory(&env.artifact_dir())?;
 
-    with_log_group("Building rustc-perf", || match env.prebuilt_rustc_perf() {
-        Some(dir) => copy_rustc_perf(env, &dir),
-        None => download_rustc_perf(env),
+    with_log_group("Building rustc-perf", || {
+        let rustc_perf_checkout_dir = match env.prebuilt_rustc_perf() {
+            Some(dir) => dir,
+            None => env.checkout_path().join("src").join("tools").join("rustc-perf"),
+        };
+        copy_rustc_perf(env, &rustc_perf_checkout_dir)
     })?;
 
     // Stage 1: Build PGO instrumented rustc
@@ -403,36 +412,6 @@
     build_rustc_perf(env)
 }
 
-// Download and build rustc-perf into the given environment.
-fn download_rustc_perf(env: &Environment) -> anyhow::Result<()> {
-    reset_directory(&env.rustc_perf_dir())?;
-
-    // FIXME: add some mechanism for synchronization of this commit SHA with
-    // Linux (which builds rustc-perf in a Dockerfile)
-    // rustc-perf version from 2023-10-22
-    const PERF_COMMIT: &str = "4f313add609f43e928e98132358e8426ed3969ae";
-
-    let url = format!("https://ci-mirrors.rust-lang.org/rustc/rustc-perf-{PERF_COMMIT}.zip");
-    let client = reqwest::blocking::Client::builder()
-        .timeout(Duration::from_secs(60 * 2))
-        .connect_timeout(Duration::from_secs(60 * 2))
-        .build()?;
-    let response = retry_action(
-        || Ok(client.get(&url).send()?.error_for_status()?.bytes()?.to_vec()),
-        "Download rustc-perf archive",
-        5,
-    )?;
-
-    let mut archive = ZipArchive::new(Cursor::new(response))?;
-    archive.extract(env.rustc_perf_dir())?;
-    move_directory(
-        &env.rustc_perf_dir().join(format!("rustc-perf-{PERF_COMMIT}")),
-        &env.rustc_perf_dir(),
-    )?;
-
-    build_rustc_perf(env)
-}
-
 fn build_rustc_perf(env: &Environment) -> anyhow::Result<()> {
     cmd(&[env.cargo_stage_0().as_str(), "build", "-p", "collector"])
         .workdir(&env.rustc_perf_dir())
diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py
index f942111..860d218 100755
--- a/src/tools/publish_toolstate.py
+++ b/src/tools/publish_toolstate.py
@@ -3,8 +3,7 @@
 
 # This script computes the new "current" toolstate for the toolstate repo (not to be
 # confused with publishing the test results, which happens in `src/bootstrap/toolstate.rs`).
-# It gets called from `src/ci/publish_toolstate.sh` when a new commit lands on `master`
-# (i.e., after it passed all checks on `auto`).
+# It gets called from `src/ci/publish_toolstate.sh` at the end of an `auto` build.
 
 from __future__ import print_function
 
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 9888ca2..9854d91 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -40,12 +40,17 @@
 
 /// Check if target is windows-like.
 pub fn is_windows() -> bool {
-    env::var_os("IS_WINDOWS").is_some()
+    target().contains("windows")
 }
 
 /// Check if target uses msvc.
 pub fn is_msvc() -> bool {
-    env::var_os("IS_MSVC").is_some()
+    target().contains("msvc")
+}
+
+/// Check if target uses macOS.
+pub fn is_darwin() -> bool {
+    target().contains("darwin")
 }
 
 /// Construct a path to a static library under `$TMPDIR` given the library name. This will return a
@@ -54,6 +59,21 @@
     tmp_dir().join(static_lib_name(name))
 }
 
+pub fn python_command() -> Command {
+    let python_path = std::env::var("PYTHON").expect("PYTHON environment variable does not exist");
+    Command::new(python_path)
+}
+
+pub fn htmldocck() -> Command {
+    let mut python = python_command();
+    python.arg(source_path().join("src/etc/htmldocck.py"));
+    python
+}
+
+pub fn source_path() -> PathBuf {
+    std::env::var("S").expect("S variable does not exist").into()
+}
+
 /// Construct the static library name based on the platform.
 pub fn static_lib_name(name: &str) -> String {
     // See tools.mk (irrelevant lines omitted):
@@ -73,9 +93,47 @@
     //     endif
     // endif
     // ```
-    assert!(!name.contains(char::is_whitespace), "name cannot contain whitespace");
+    assert!(!name.contains(char::is_whitespace), "static library name cannot contain whitespace");
 
-    if target().contains("msvc") { format!("{name}.lib") } else { format!("lib{name}.a") }
+    if is_msvc() { format!("{name}.lib") } else { format!("lib{name}.a") }
+}
+
+/// Construct a path to a dynamic library under `$TMPDIR` given the library name. This will return a
+/// path with `$TMPDIR` joined with platform-and-compiler-specific library name.
+pub fn dynamic_lib(name: &str) -> PathBuf {
+    tmp_dir().join(dynamic_lib_name(name))
+}
+
+/// Construct the dynamic library name based on the platform.
+pub fn dynamic_lib_name(name: &str) -> String {
+    // See tools.mk (irrelevant lines omitted):
+    //
+    // ```makefile
+    // ifeq ($(UNAME),Darwin)
+    //     DYLIB = $(TMPDIR)/lib$(1).dylib
+    // else
+    //     ifdef IS_WINDOWS
+    //         DYLIB = $(TMPDIR)/$(1).dll
+    //     else
+    //         DYLIB = $(TMPDIR)/lib$(1).so
+    //     endif
+    // endif
+    // ```
+    assert!(!name.contains(char::is_whitespace), "dynamic library name cannot contain whitespace");
+
+    if is_darwin() {
+        format!("lib{name}.dylib")
+    } else if is_windows() {
+        format!("{name}.dll")
+    } else {
+        format!("lib{name}.so")
+    }
+}
+
+/// Construct a path to a rust library (rlib) under `$TMPDIR` given the library name. This will return a
+/// path with `$TMPDIR` joined with the library name.
+pub fn rust_lib(name: &str) -> PathBuf {
+    tmp_dir().join(format!("lib{name}.rlib"))
 }
 
 /// Construct the binary name based on platform.
diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs
index de773d6..f581204 100644
--- a/src/tools/run-make-support/src/rustc.rs
+++ b/src/tools/run-make-support/src/rustc.rs
@@ -1,5 +1,5 @@
 use std::env;
-use std::ffi::OsString;
+use std::ffi::{OsStr, OsString};
 use std::io::Write;
 use std::path::Path;
 use std::process::{Command, Output, Stdio};
@@ -64,6 +64,12 @@
         self
     }
 
+    /// Specify a specific optimization level.
+    pub fn opt_level(&mut self, option: &str) -> &mut Self {
+        self.cmd.arg(format!("-Copt-level={option}"));
+        self
+    }
+
     /// Specify type(s) of output files to generate.
     pub fn emit(&mut self, kinds: &str) -> &mut Self {
         self.cmd.arg(format!("--emit={kinds}"));
@@ -91,7 +97,7 @@
         self
     }
 
-    /// Specify path to the output file.
+    /// Specify path to the output file. Equivalent to `-o`` in rustc.
     pub fn output<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
         self.cmd.arg("-o");
         self.cmd.arg(path.as_ref());
@@ -150,6 +156,13 @@
         self
     }
 
+    /// Add a directory to the library search path. Equivalent to `-L`` in rustc.
+    pub fn library_search_path<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg("-L");
+        self.cmd.arg(path.as_ref());
+        self
+    }
+
     /// Specify the edition year.
     pub fn edition(&mut self, edition: &str) -> &mut Self {
         self.cmd.arg("--edition");
@@ -176,6 +189,13 @@
         self
     }
 
+    /// Specify the crate name.
+    pub fn crate_name<S: AsRef<OsStr>>(&mut self, name: S) -> &mut Self {
+        self.cmd.arg("--crate-name");
+        self.cmd.arg(name.as_ref());
+        self
+    }
+
     /// Get the [`Output`][::std::process::Output] of the finished process.
     #[track_caller]
     pub fn command_output(&mut self) -> ::std::process::Output {
diff --git a/src/tools/run-make-support/src/rustdoc.rs b/src/tools/run-make-support/src/rustdoc.rs
index aa3c7dc..c4f4e9f 100644
--- a/src/tools/run-make-support/src/rustdoc.rs
+++ b/src/tools/run-make-support/src/rustdoc.rs
@@ -1,4 +1,5 @@
 use std::env;
+use std::ffi::OsStr;
 use std::io::Write;
 use std::path::Path;
 use std::process::{Command, Output, Stdio};
@@ -45,6 +46,21 @@
         Self { cmd, stdin: None }
     }
 
+    /// Specify where an external library is located.
+    pub fn extern_<P: AsRef<Path>>(&mut self, crate_name: &str, path: P) -> &mut Self {
+        assert!(
+            !crate_name.contains(|c: char| c.is_whitespace() || c == '\\' || c == '/'),
+            "crate name cannot contain whitespace or path separators"
+        );
+
+        let path = path.as_ref().to_string_lossy();
+
+        self.cmd.arg("--extern");
+        self.cmd.arg(format!("{crate_name}={path}"));
+
+        self
+    }
+
     /// Specify path to the input file.
     pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
         self.cmd.arg(path.as_ref());
@@ -107,6 +123,34 @@
         self
     }
 
+    /// Specify the target triple, or a path to a custom target json spec file.
+    pub fn target(&mut self, target: &str) -> &mut Self {
+        self.cmd.arg(format!("--target={target}"));
+        self
+    }
+
+    /// Specify the crate type.
+    pub fn crate_type(&mut self, crate_type: &str) -> &mut Self {
+        self.cmd.arg("--crate-type");
+        self.cmd.arg(crate_type);
+        self
+    }
+
+    /// Specify the crate name.
+    pub fn crate_name<S: AsRef<OsStr>>(&mut self, name: S) -> &mut Self {
+        self.cmd.arg("--crate-name");
+        self.cmd.arg(name.as_ref());
+        self
+    }
+
+    /// Add a directory to the library search path. It corresponds to the `-L`
+    /// rustdoc option.
+    pub fn library_search_path<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg("-L");
+        self.cmd.arg(path.as_ref());
+        self
+    }
+
     #[track_caller]
     pub fn run_fail_assert_exit_code(&mut self, code: i32) -> Output {
         let caller_location = std::panic::Location::caller();
diff --git a/src/tools/rust-analyzer/.git-blame-ignore-revs b/src/tools/rust-analyzer/.git-blame-ignore-revs
index a302e23..d5951a9 100644
--- a/src/tools/rust-analyzer/.git-blame-ignore-revs
+++ b/src/tools/rust-analyzer/.git-blame-ignore-revs
@@ -6,3 +6,10 @@
 
 # prettier format
 f247090558c9ba3c551566eae5882b7ca865225f
+
+# subtree syncs
+932d85b52946d917deab2c23ead552f7f713b828
+3e358a6827d83e8d6473913a5e304734aadfed04
+9d2cb42a413e51deb50b36794a2e1605381878fc
+f532576ac53ddcc666bc8d59e0b6437065e2f599
+c48062fe2ab9a2d913d1985a6b0aec4bf936bfc1
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index a10345a..87a1729 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -63,15 +63,15 @@
       - name: Install Rust toolchain
         run: |
           rustup update --no-self-update ${{ env.RUST_CHANNEL }}
-          rustup component add --toolchain ${{ env.RUST_CHANNEL }} rustfmt rust-src
           rustup default ${{ env.RUST_CHANNEL }}
+          rustup component add --toolchain ${{ env.RUST_CHANNEL }} rustfmt rust-src
       # https://github.com/actions-rust-lang/setup-rust-toolchain/blob/main/rust.json
       - name: Install Rust Problem Matcher
         if: matrix.os == 'ubuntu-latest'
         run: echo "::add-matcher::.github/rust.json"
 
       - name: Cache Dependencies
-        uses: Swatinem/rust-cache@640a22190e7a783d4c409684cea558f081f92012
+        uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609
         with:
           key: ${{ env.RUST_CHANNEL }}
 
@@ -140,7 +140,7 @@
           rustup target add ${{ env.targets }} ${{ env.targets_ide }}
 
       - name: Cache Dependencies
-        uses: Swatinem/rust-cache@640a22190e7a783d4c409684cea558f081f92012
+        uses: Swatinem/rust-cache@9bdad043e88c75890e36ad3bbc8d27f0090dd609
 
       - name: Check
         run: |
diff --git a/src/tools/rust-analyzer/.github/workflows/metrics.yaml b/src/tools/rust-analyzer/.github/workflows/metrics.yaml
index b6cd4a7..a4146d6 100644
--- a/src/tools/rust-analyzer/.github/workflows/metrics.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/metrics.yaml
@@ -11,34 +11,21 @@
   RUSTUP_MAX_RETRIES: 10
 
 jobs:
-  setup_cargo:
+  build_metrics:
     if: github.repository == 'rust-lang/rust-analyzer'
     runs-on: ubuntu-latest
+
     steps:
       - name: Install Rust toolchain
         run: |
           rustup update --no-self-update stable
-          rustup component add rustfmt rust-src
           rustup default stable
-      - name: Cache cargo
-        uses: actions/cache@v4
-        with:
-          path: |
-            ~/.cargo/bin/
-            ~/.cargo/registry/index/
-            ~/.cargo/registry/cache/
-            ~/.cargo/git/db/
-          key: ${{ runner.os }}-cargo-${{ github.sha }}
+          rustup component add --toolchain stable rust-src
 
-  build_metrics:
-    runs-on: ubuntu-latest
-    needs: setup_cargo
-
-    steps:
       - name: Checkout repository
         uses: actions/checkout@v4
 
-      - name: Restore cargo cache
+      - name: Cache cargo
         uses: actions/cache@v4
         with:
           path: |
@@ -69,22 +56,18 @@
       matrix:
         names: [self, ripgrep-13.0.0, webrender-2022, diesel-1.4.8, hyper-0.14.18]
     runs-on: ubuntu-latest
-    needs: [setup_cargo, build_metrics]
+    needs: build_metrics
 
     steps:
+      - name: Install Rust toolchain
+        run: |
+          rustup update --no-self-update stable
+          rustup default stable
+          rustup component add --toolchain stable rust-src
+
       - name: Checkout repository
         uses: actions/checkout@v4
 
-      - name: Restore cargo cache
-        uses: actions/cache@v4
-        with:
-          path: |
-            ~/.cargo/bin/
-            ~/.cargo/registry/index/
-            ~/.cargo/registry/cache/
-            ~/.cargo/git/db/
-          key: ${{ runner.os }}-cargo-${{ github.sha }}
-
       - name: Restore target cache
         uses: actions/cache@v4
         with:
diff --git a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml
index 12a1a79..f975bba 100644
--- a/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/rustdoc.yaml
@@ -26,7 +26,7 @@
       run: cargo doc --all --no-deps
 
     - name: Deploy Docs
-      uses: peaceiris/actions-gh-pages@364c31d33bb99327c77b3a5438a83a357a6729ad # v3.4.0
+      uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0
       with:
         github_token: ${{ secrets.GITHUB_TOKEN }}
         publish_branch: gh-pages
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index a6e4601..8eb8725 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -28,9 +28,9 @@
 
 [[package]]
 name = "anyhow"
-version = "1.0.80"
+version = "1.0.83"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
+checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3"
 
 [[package]]
 name = "arbitrary"
@@ -46,15 +46,15 @@
 
 [[package]]
 name = "autocfg"
-version = "1.1.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
 
 [[package]]
 name = "backtrace"
-version = "0.3.69"
+version = "0.3.71"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
+checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d"
 dependencies = [
  "addr2line",
  "cc",
@@ -91,9 +91,9 @@
 
 [[package]]
 name = "bitflags"
-version = "2.4.2"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
+checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
 
 [[package]]
 name = "byteorder"
@@ -112,9 +112,9 @@
 
 [[package]]
 name = "cargo-platform"
-version = "0.1.7"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f"
+checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc"
 dependencies = [
  "serde",
 ]
@@ -135,9 +135,9 @@
 
 [[package]]
 name = "cc"
-version = "1.0.90"
+version = "1.0.97"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5"
+checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4"
 
 [[package]]
 name = "cfg"
@@ -160,6 +160,12 @@
 checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
+name = "cfg_aliases"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
+
+[[package]]
 name = "chalk-derive"
 version = "0.97.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -177,7 +183,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "db18493569b190f7266a04901e520fc3a5c00564475154287906f8a27302c119"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "chalk-derive",
 ]
 
@@ -282,11 +288,11 @@
 
 [[package]]
 name = "ctrlc"
-version = "3.4.2"
+version = "3.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b467862cc8610ca6fc9a1532d7777cee0804e678ab45410897b9396495994a0b"
+checksum = "672465ae37dc1bc6380a6547a8883d5dd397b0f1faaad4f265726cc7042a5345"
 dependencies = [
- "nix 0.27.1",
+ "nix 0.28.0",
  "windows-sys 0.52.0",
 ]
 
@@ -324,10 +330,31 @@
 ]
 
 [[package]]
-name = "dissimilar"
-version = "1.0.7"
+name = "directories"
+version = "5.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86e3bdc80eee6e16b2b6b0f87fbc98c04bee3455e35174c0de1a125d0688c632"
+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 = "dissimilar"
+version = "1.0.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59f8e79d1fbf76bdfbde321e902714bf6c49df88a7dda6fc682fc2979226962d"
 
 [[package]]
 name = "dot"
@@ -343,15 +370,15 @@
 
 [[package]]
 name = "either"
-version = "1.10.0"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
+checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
 
 [[package]]
 name = "ena"
-version = "0.14.2"
+version = "0.14.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
+checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5"
 dependencies = [
  "log",
 ]
@@ -364,9 +391,9 @@
 
 [[package]]
 name = "expect-test"
-version = "1.4.1"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30d9eafeadd538e68fb28016364c9732d78e420b9ff8853fa5e4058861e9f8d3"
+checksum = "9e0be0a561335815e06dab7c62e50353134c796e7a6155402a64bcff66b6a5e0"
 dependencies = [
  "dissimilar",
  "once_cell",
@@ -380,7 +407,7 @@
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.4.1",
  "windows-sys 0.52.0",
 ]
 
@@ -392,9 +419,9 @@
 
 [[package]]
 name = "flate2"
-version = "1.0.28"
+version = "1.0.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
+checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae"
 dependencies = [
  "crc32fast",
  "miniz_oxide",
@@ -442,9 +469,9 @@
 
 [[package]]
 name = "getrandom"
-version = "0.2.12"
+version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
 dependencies = [
  "cfg-if",
  "libc",
@@ -459,9 +486,9 @@
 
 [[package]]
 name = "hashbrown"
-version = "0.14.3"
+version = "0.14.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
 
 [[package]]
 name = "heck"
@@ -504,7 +531,7 @@
 dependencies = [
  "arrayvec",
  "base-db",
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "cfg",
  "cov-mark",
  "dashmap",
@@ -568,7 +595,7 @@
 dependencies = [
  "arrayvec",
  "base-db",
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "chalk-derive",
  "chalk-ir",
  "chalk-recursive",
@@ -589,7 +616,7 @@
  "oorandom",
  "project-model",
  "ra-ap-rustc_abi",
- "ra-ap-rustc_index",
+ "ra-ap-rustc_index 0.53.0",
  "ra-ap-rustc_pattern_analysis",
  "rustc-hash",
  "scoped-tls",
@@ -695,7 +722,7 @@
 dependencies = [
  "arrayvec",
  "base-db",
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "cov-mark",
  "crossbeam-channel",
  "either",
@@ -776,9 +803,9 @@
 
 [[package]]
 name = "indexmap"
-version = "2.2.5"
+version = "2.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
+checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -826,9 +853,9 @@
 
 [[package]]
 name = "itoa"
-version = "1.0.10"
+version = "1.0.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
 [[package]]
 name = "jod-thread"
@@ -874,9 +901,9 @@
 
 [[package]]
 name = "libc"
-version = "0.2.153"
+version = "0.2.154"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
+checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
 
 [[package]]
 name = "libloading"
@@ -885,20 +912,30 @@
 checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19"
 dependencies = [
  "cfg-if",
- "windows-targets 0.52.4",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
 name = "libmimalloc-sys"
-version = "0.1.35"
+version = "0.1.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3979b5c37ece694f1f5e51e7ecc871fdb0f517ed04ee45f88d15d6d553cb9664"
+checksum = "81eb4061c0582dedea1cbc7aff2240300dd6982e0239d1c99e65c1dbf4a30ba7"
 dependencies = [
  "cc",
  "libc",
 ]
 
 [[package]]
+name = "libredox"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
+dependencies = [
+ "bitflags 2.5.0",
+ "libc",
+]
+
+[[package]]
 name = "limit"
 version = "0.0.0"
 
@@ -948,9 +985,9 @@
 
 [[package]]
 name = "lock_api"
-version = "0.4.11"
+version = "0.4.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -1001,9 +1038,9 @@
 
 [[package]]
 name = "lz4_flex"
-version = "0.11.2"
+version = "0.11.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "912b45c753ff5f7f5208307e8ace7d2a2e30d024e26d3509f3dce546c044ce15"
+checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5"
 
 [[package]]
 name = "mbe"
@@ -1023,9 +1060,9 @@
 
 [[package]]
 name = "memchr"
-version = "2.7.1"
+version = "2.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
+checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
 
 [[package]]
 name = "memmap2"
@@ -1038,18 +1075,18 @@
 
 [[package]]
 name = "memoffset"
-version = "0.9.0"
+version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
 dependencies = [
  "autocfg",
 ]
 
 [[package]]
 name = "mimalloc"
-version = "0.1.39"
+version = "0.1.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fa01922b5ea280a911e323e4d2fd24b7fe5cc4042e0d2cda3c40775cdc4bdc9c"
+checksum = "9f41a2280ded0da56c8cf898babb86e8f10651a34adcfff190ae9a1159c6908d"
 dependencies = [
  "libmimalloc-sys",
 ]
@@ -1097,12 +1134,13 @@
 
 [[package]]
 name = "nix"
-version = "0.27.1"
+version = "0.28.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
+checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "cfg-if",
+ "cfg_aliases",
  "libc",
 ]
 
@@ -1118,7 +1156,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "crossbeam-channel",
  "filetime",
  "fsevent-sys",
@@ -1187,10 +1225,16 @@
 checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
 
 [[package]]
-name = "parking_lot"
-version = "0.12.1"
+name = "option-ext"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
+
+[[package]]
+name = "parking_lot"
+version = "0.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb"
 dependencies = [
  "lock_api",
  "parking_lot_core",
@@ -1198,15 +1242,15 @@
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.9"
+version = "0.9.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall",
+ "redox_syscall 0.5.1",
  "smallvec",
- "windows-targets 0.48.5",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
@@ -1224,9 +1268,9 @@
 
 [[package]]
 name = "paste"
-version = "1.0.14"
+version = "1.0.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
 
 [[package]]
 name = "paths"
@@ -1262,9 +1306,9 @@
 
 [[package]]
 name = "petgraph"
-version = "0.6.4"
+version = "0.6.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
+checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db"
 dependencies = [
  "fixedbitset",
  "indexmap",
@@ -1272,9 +1316,9 @@
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.13"
+version = "0.2.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
+checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
 
 [[package]]
 name = "powerfmt"
@@ -1346,9 +1390,9 @@
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.78"
+version = "1.0.82"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
+checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
 dependencies = [
  "unicode-ident",
 ]
@@ -1365,7 +1409,7 @@
  "perf-event",
  "tikv-jemalloc-ctl",
  "tracing",
- "winapi",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -1417,7 +1461,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
 dependencies = [
- "bitflags 2.4.2",
+ "bitflags 2.5.0",
  "memchr",
  "unicase",
 ]
@@ -1433,21 +1477,21 @@
 
 [[package]]
 name = "quote"
-version = "1.0.35"
+version = "1.0.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
 dependencies = [
  "proc-macro2",
 ]
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.44.0"
+version = "0.53.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b8709df2a746f055316bc0c62bd30948695a25e734863bf6e1f9755403e010ab"
+checksum = "80b1d613eee933486c0613a7bc26e515e46f43adf479d1edd5e537f983e9ce46"
 dependencies = [
- "bitflags 2.4.2",
- "ra-ap-rustc_index",
+ "bitflags 2.5.0",
+ "ra-ap-rustc_index 0.53.0",
  "tracing",
 ]
 
@@ -1458,7 +1502,18 @@
 checksum = "9ad68bacffb87dcdbb23a3ce11261375078aaa06b85d348c49f39ffd5510dc20"
 dependencies = [
  "arrayvec",
- "ra-ap-rustc_index_macros",
+ "ra-ap-rustc_index_macros 0.44.0",
+ "smallvec",
+]
+
+[[package]]
+name = "ra-ap-rustc_index"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f072060ac77e9e1a02cc20028095993af7e72cc0804779c68bcbf47b16de49c9"
+dependencies = [
+ "arrayvec",
+ "ra-ap-rustc_index_macros 0.53.0",
  "smallvec",
 ]
 
@@ -1475,10 +1530,22 @@
 ]
 
 [[package]]
-name = "ra-ap-rustc_lexer"
-version = "0.44.0"
+name = "ra-ap-rustc_index_macros"
+version = "0.53.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aab683fc8579d09eb72033bd5dc9ba6d701aa9645b5fed087ef19af71184dff3"
+checksum = "82f3d6dcb30a66905388e14756b8f2216131d9f8004922c07f13335840e058d1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
+]
+
+[[package]]
+name = "ra-ap-rustc_lexer"
+version = "0.53.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dbd8a2b0bdcba9892cbce0b25f6c953d31b0febc1f3420fc692884fce5a23ad8"
 dependencies = [
  "unicode-properties",
  "unicode-xid",
@@ -1486,11 +1553,11 @@
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.44.0"
+version = "0.53.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bcf9ff5edbf784b67b8ad5e03a068f1300fcc24062c0d476b3018965135d933"
+checksum = "70dad7a491c2554590222e0c9212dcb7c2e7aceb668875075012a35ea780d135"
 dependencies = [
- "ra-ap-rustc_index",
+ "ra-ap-rustc_index 0.53.0",
  "ra-ap-rustc_lexer",
 ]
 
@@ -1500,7 +1567,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d63d1e1d5b2a13273cee1a10011147418f40e12b70f70578ce1dee0f1cafc334"
 dependencies = [
- "ra-ap-rustc_index",
+ "ra-ap-rustc_index 0.44.0",
  "rustc-hash",
  "rustc_apfloat",
  "smallvec",
@@ -1539,9 +1606,9 @@
 
 [[package]]
 name = "rayon"
-version = "1.9.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4963ed1bc86e4f3ee217022bd855b297cef07fb9eac5dfa1f788b220b49b3bd"
+checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
 dependencies = [
  "either",
  "rayon-core",
@@ -1567,6 +1634,26 @@
 ]
 
 [[package]]
+name = "redox_syscall"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e"
+dependencies = [
+ "bitflags 2.5.0",
+]
+
+[[package]]
+name = "redox_users"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891"
+dependencies = [
+ "getrandom",
+ "libredox",
+ "thiserror",
+]
+
+[[package]]
 name = "rowan"
 version = "0.15.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1634,16 +1721,16 @@
  "vfs",
  "vfs-notify",
  "walkdir",
- "winapi",
+ "windows-sys 0.52.0",
  "xflags",
  "xshell",
 ]
 
 [[package]]
 name = "rustc-demangle"
-version = "0.1.23"
+version = "0.1.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
+checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
 
 [[package]]
 name = "rustc-hash"
@@ -1663,9 +1750,9 @@
 
 [[package]]
 name = "ryu"
-version = "1.0.17"
+version = "1.0.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
 
 [[package]]
 name = "salsa"
@@ -1729,27 +1816,27 @@
 
 [[package]]
 name = "semver"
-version = "1.0.22"
+version = "1.0.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "serde"
-version = "1.0.197"
+version = "1.0.201"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
+checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.197"
+version = "1.0.201"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
+checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1758,9 +1845,9 @@
 
 [[package]]
 name = "serde_json"
-version = "1.0.114"
+version = "1.0.117"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0"
+checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
 dependencies = [
  "indexmap",
  "itoa",
@@ -1770,9 +1857,9 @@
 
 [[package]]
 name = "serde_repr"
-version = "0.1.18"
+version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb"
+checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1799,9 +1886,9 @@
 
 [[package]]
 name = "smallvec"
-version = "1.13.1"
+version = "1.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
 
 [[package]]
 name = "smol_str"
@@ -1856,14 +1943,14 @@
  "jod-thread",
  "libc",
  "miow",
- "winapi",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "syn"
-version = "2.0.52"
+version = "2.0.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
+checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1946,18 +2033,18 @@
 
 [[package]]
 name = "thiserror"
-version = "1.0.57"
+version = "1.0.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
+checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.57"
+version = "1.0.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
+checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2007,9 +2094,9 @@
 
 [[package]]
 name = "time"
-version = "0.3.34"
+version = "0.3.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
+checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
 dependencies = [
  "deranged",
  "num-conv",
@@ -2041,9 +2128,9 @@
 
 [[package]]
 name = "toml"
-version = "0.8.8"
+version = "0.8.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35"
+checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
 dependencies = [
  "serde",
  "serde_spanned",
@@ -2062,9 +2149,9 @@
 
 [[package]]
 name = "toml_edit"
-version = "0.21.0"
+version = "0.22.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03"
+checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef"
 dependencies = [
  "indexmap",
  "serde",
@@ -2255,6 +2342,7 @@
  "paths",
  "rustc-hash",
  "stdx",
+ "tracing",
 ]
 
 [[package]]
@@ -2304,11 +2392,11 @@
 
 [[package]]
 name = "winapi-util"
-version = "0.1.6"
+version = "0.1.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
 dependencies = [
- "winapi",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -2332,7 +2420,7 @@
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.4",
+ "windows-targets 0.52.5",
 ]
 
 [[package]]
@@ -2352,17 +2440,18 @@
 
 [[package]]
 name = "windows-targets"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.4",
- "windows_aarch64_msvc 0.52.4",
- "windows_i686_gnu 0.52.4",
- "windows_i686_msvc 0.52.4",
- "windows_x86_64_gnu 0.52.4",
- "windows_x86_64_gnullvm 0.52.4",
- "windows_x86_64_msvc 0.52.4",
+ "windows_aarch64_gnullvm 0.52.5",
+ "windows_aarch64_msvc 0.52.5",
+ "windows_i686_gnu 0.52.5",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc 0.52.5",
+ "windows_x86_64_gnu 0.52.5",
+ "windows_x86_64_gnullvm 0.52.5",
+ "windows_x86_64_msvc 0.52.5",
 ]
 
 [[package]]
@@ -2373,9 +2462,9 @@
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -2385,9 +2474,9 @@
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -2397,9 +2486,15 @@
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -2409,9 +2504,9 @@
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -2421,9 +2516,9 @@
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
@@ -2433,9 +2528,9 @@
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -2445,15 +2540,15 @@
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.52.4"
+version = "0.52.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
 
 [[package]]
 name = "winnow"
-version = "0.5.32"
+version = "0.6.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8434aeec7b290e8da5c3f0d628cb0eac6cabcb31d14bb74f779a08109a5914d6"
+checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d"
 dependencies = [
  "memchr",
 ]
@@ -2481,24 +2576,25 @@
 
 [[package]]
 name = "xshell"
-version = "0.2.5"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce2107fe03e558353b4c71ad7626d58ed82efaf56c54134228608893c77023ad"
+checksum = "6db0ab86eae739efd1b054a8d3d16041914030ac4e01cd1dca0cf252fd8b6437"
 dependencies = [
  "xshell-macros",
 ]
 
 [[package]]
 name = "xshell-macros"
-version = "0.2.5"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e2c411759b501fb9501aac2b1b2d287a6e93e5bdcf13c25306b23e1b716dd0e"
+checksum = "9d422e8e38ec76e2f06ee439ccc765e9c6a9638b9e7c9f2e8255e4d41e8bd852"
 
 [[package]]
 name = "xtask"
 version = "0.1.0"
 dependencies = [
  "anyhow",
+ "directories",
  "flate2",
  "itertools",
  "proc-macro2",
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index f7e3ae5..3108c1b 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -4,7 +4,7 @@
 resolver = "2"
 
 [workspace.package]
-rust-version = "1.76"
+rust-version = "1.78"
 edition = "2021"
 license = "MIT OR Apache-2.0"
 authors = ["rust-analyzer team"]
@@ -85,10 +85,10 @@
 vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
 vfs = { path = "./crates/vfs", version = "0.0.0" }
 
-ra-ap-rustc_lexer = { version = "0.44.0", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.44.0", default-features = false }
-ra-ap-rustc_index = { version = "0.44.0", default-features = false }
-ra-ap-rustc_abi = { version = "0.44.0", default-features = false }
+ra-ap-rustc_lexer = { version = "0.53.0", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.53.0", default-features = false }
+ra-ap-rustc_index = { version = "0.53.0", default-features = false }
+ra-ap-rustc_abi = { version = "0.53.0", default-features = false }
 ra-ap-rustc_pattern_analysis = { version = "0.44.0", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
diff --git a/src/tools/rust-analyzer/crates/base-db/src/change.rs b/src/tools/rust-analyzer/crates/base-db/src/change.rs
index f202a88..927b210 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/change.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/change.rs
@@ -51,7 +51,7 @@
     }
 
     pub fn apply(self, db: &mut dyn SourceDatabaseExt) {
-        let _p = tracing::span!(tracing::Level::INFO, "RootDatabase::apply_change").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "FileChange::apply").entered();
         if let Some(roots) = self.roots {
             for (idx, root) in roots.into_iter().enumerate() {
                 let root_id = SourceRootId(idx as u32);
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index 240af79..b2c3f38 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -324,21 +324,27 @@
     pub crate_id: CrateId,
     pub name: CrateName,
     prelude: bool,
+    sysroot: bool,
 }
 
 impl Dependency {
     pub fn new(name: CrateName, crate_id: CrateId) -> Self {
-        Self { name, crate_id, prelude: true }
+        Self { name, crate_id, prelude: true, sysroot: false }
     }
 
-    pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool) -> Self {
-        Self { name, crate_id, prelude }
+    pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool, sysroot: bool) -> Self {
+        Self { name, crate_id, prelude, sysroot }
     }
 
     /// Whether this dependency is to be added to the depending crate's extern prelude.
     pub fn is_prelude(&self) -> bool {
         self.prelude
     }
+
+    /// Whether this dependency is a sysroot injected one.
+    pub fn is_sysroot(&self) -> bool {
+        self.sysroot
+    }
 }
 
 impl CrateGraph {
diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
index 2b64a07..2c13eed 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
@@ -8,7 +8,7 @@
 use std::panic;
 
 use salsa::Durability;
-use syntax::{ast, Parse, SourceFile};
+use syntax::{ast, Parse, SourceFile, SyntaxError};
 use triomphe::Arc;
 
 pub use crate::{
@@ -51,6 +51,7 @@
     /// Text of the file.
     fn file_text(&self, file_id: FileId) -> Arc<str>;
     fn resolve_path(&self, path: AnchoredPath<'_>) -> Option<FileId>;
+    /// Crates whose root's source root is the same as the source root of `file_id`
     fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]>;
 }
 
@@ -61,6 +62,9 @@
     /// Parses the file into the syntax tree.
     fn parse(&self, file_id: FileId) -> Parse<ast::SourceFile>;
 
+    /// Returns the set of errors obtained from parsing the file including validation errors.
+    fn parse_errors(&self, file_id: FileId) -> Option<Arc<[SyntaxError]>>;
+
     /// The crate graph.
     #[salsa::input]
     fn crate_graph(&self) -> Arc<CrateGraph>;
@@ -81,12 +85,20 @@
 }
 
 fn parse(db: &dyn SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
-    let _p = tracing::span!(tracing::Level::INFO, "parse_query", ?file_id).entered();
+    let _p = tracing::span!(tracing::Level::INFO, "parse", ?file_id).entered();
     let text = db.file_text(file_id);
     // FIXME: Edition based parsing
     SourceFile::parse(&text, span::Edition::CURRENT)
 }
 
+fn parse_errors(db: &dyn SourceDatabase, file_id: FileId) -> Option<Arc<[SyntaxError]>> {
+    let errors = db.parse(file_id).errors();
+    match &*errors {
+        [] => None,
+        [..] => Some(errors.into()),
+    }
+}
+
 /// We don't want to give HIR knowledge of source roots, hence we extract these
 /// methods into a separate DB.
 #[salsa::query_group(SourceDatabaseExtStorage)]
@@ -104,6 +116,7 @@
     #[salsa::input]
     fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
 
+    /// Crates whose root fool is in `id`.
     fn source_root_crates(&self, id: SourceRootId) -> Arc<[CrateId]>;
 }
 
diff --git a/src/tools/rust-analyzer/crates/cfg/src/tests.rs b/src/tools/rust-analyzer/crates/cfg/src/tests.rs
index a1ae15f..dddaf2c 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/tests.rs
@@ -1,6 +1,6 @@
 use arbitrary::{Arbitrary, Unstructured};
 use expect_test::{expect, Expect};
-use mbe::{syntax_node_to_token_tree, DummyTestSpanMap, DUMMY};
+use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode, DummyTestSpanMap, DUMMY};
 use syntax::{ast, AstNode, Edition};
 
 use crate::{CfgAtom, CfgExpr, CfgOptions, DnfExpr};
@@ -8,7 +8,12 @@
 fn assert_parse_result(input: &str, expected: CfgExpr) {
     let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap();
     let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
-    let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY);
+    let tt = syntax_node_to_token_tree(
+        tt.syntax(),
+        DummyTestSpanMap,
+        DUMMY,
+        DocCommentDesugarMode::ProcMacro,
+    );
     let cfg = CfgExpr::parse(&tt);
     assert_eq!(cfg, expected);
 }
@@ -16,7 +21,12 @@
 fn check_dnf(input: &str, expect: Expect) {
     let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap();
     let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
-    let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY);
+    let tt = syntax_node_to_token_tree(
+        tt.syntax(),
+        DummyTestSpanMap,
+        DUMMY,
+        DocCommentDesugarMode::ProcMacro,
+    );
     let cfg = CfgExpr::parse(&tt);
     let actual = format!("#![cfg({})]", DnfExpr::new(cfg));
     expect.assert_eq(&actual);
@@ -25,7 +35,12 @@
 fn check_why_inactive(input: &str, opts: &CfgOptions, expect: Expect) {
     let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap();
     let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
-    let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY);
+    let tt = syntax_node_to_token_tree(
+        tt.syntax(),
+        DummyTestSpanMap,
+        DUMMY,
+        DocCommentDesugarMode::ProcMacro,
+    );
     let cfg = CfgExpr::parse(&tt);
     let dnf = DnfExpr::new(cfg);
     let why_inactive = dnf.why_inactive(opts).unwrap().to_string();
@@ -36,7 +51,12 @@
 fn check_enable_hints(input: &str, opts: &CfgOptions, expected_hints: &[&str]) {
     let source_file = ast::SourceFile::parse(input, Edition::CURRENT).ok().unwrap();
     let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
-    let tt = syntax_node_to_token_tree(tt.syntax(), DummyTestSpanMap, DUMMY);
+    let tt = syntax_node_to_token_tree(
+        tt.syntax(),
+        DummyTestSpanMap,
+        DUMMY,
+        DocCommentDesugarMode::ProcMacro,
+    );
     let cfg = CfgExpr::parse(&tt);
     let dnf = DnfExpr::new(cfg);
     let hints = dnf.compute_enable_hints(opts).map(|diff| diff.to_string()).collect::<Vec<_>>();
diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
index 5dfaaf7..6d5ca83 100644
--- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
@@ -125,8 +125,10 @@
         config: FlycheckConfig,
         sysroot_root: Option<AbsPathBuf>,
         workspace_root: AbsPathBuf,
+        manifest_path: Option<AbsPathBuf>,
     ) -> FlycheckHandle {
-        let actor = FlycheckActor::new(id, sender, config, sysroot_root, workspace_root);
+        let actor =
+            FlycheckActor::new(id, sender, config, sysroot_root, workspace_root, manifest_path);
         let (sender, receiver) = unbounded::<StateChange>();
         let thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker)
             .name("Flycheck".to_owned())
@@ -205,6 +207,7 @@
     id: usize,
     sender: Box<dyn Fn(Message) + Send>,
     config: FlycheckConfig,
+    manifest_path: Option<AbsPathBuf>,
     /// Either the workspace root of the workspace we are flychecking,
     /// or the project root of the project.
     root: AbsPathBuf,
@@ -233,6 +236,7 @@
         config: FlycheckConfig,
         sysroot_root: Option<AbsPathBuf>,
         workspace_root: AbsPathBuf,
+        manifest_path: Option<AbsPathBuf>,
     ) -> FlycheckActor {
         tracing::info!(%id, ?workspace_root, "Spawning flycheck");
         FlycheckActor {
@@ -241,6 +245,7 @@
             config,
             sysroot_root,
             root: workspace_root,
+            manifest_path,
             command_handle: None,
             command_receiver: None,
         }
@@ -388,8 +393,13 @@
                     "--message-format=json"
                 });
 
-                cmd.arg("--manifest-path");
-                cmd.arg(self.root.join("Cargo.toml"));
+                if let Some(manifest_path) = &self.manifest_path {
+                    cmd.arg("--manifest-path");
+                    cmd.arg(manifest_path);
+                    if manifest_path.extension().map_or(false, |ext| ext == "rs") {
+                        cmd.arg("-Zscript");
+                    }
+                }
 
                 options.apply_on_command(&mut cmd);
                 (cmd, options.extra_args.clone())
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs
index 9b68797..727f442 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs
@@ -5,7 +5,7 @@
 
 use base_db::FileId;
 use hir_expand::span_map::{RealSpanMap, SpanMap};
-use mbe::syntax_node_to_token_tree;
+use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode};
 use syntax::{ast, AstNode, TextRange};
 
 use crate::attr::{DocAtom, DocExpr};
@@ -18,6 +18,7 @@
         tt.syntax(),
         map.as_ref(),
         map.span_for_range(TextRange::empty(0.into())),
+        DocCommentDesugarMode::ProcMacro,
     );
     let cfg = DocExpr::parse(&tt);
     assert_eq!(cfg, expected);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
index c9f1add..d2f4d7b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs
@@ -10,9 +10,10 @@
 
 use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
-use hir_expand::{name::Name, HirFileId, InFile};
+use hir_expand::{name::Name, InFile};
 use la_arena::{Arena, ArenaMap};
 use rustc_hash::FxHashMap;
+use span::MacroFileId;
 use syntax::{ast, AstPtr, SyntaxNodePtr};
 use triomphe::Arc;
 
@@ -98,7 +99,7 @@
 
     format_args_template_map: FxHashMap<ExprId, Vec<(syntax::TextRange, Name)>>,
 
-    expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
+    expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, MacroFileId>,
 
     /// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in
     /// the source map (since they're just as volatile).
@@ -349,11 +350,17 @@
         self.expr_map.get(&src).cloned()
     }
 
-    pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<HirFileId> {
+    pub fn node_macro_file(&self, node: InFile<&ast::MacroCall>) -> Option<MacroFileId> {
         let src = node.map(AstPtr::new);
         self.expansions.get(&src).cloned()
     }
 
+    pub fn macro_calls(
+        &self,
+    ) -> impl Iterator<Item = (InFile<AstPtr<ast::MacroCall>>, MacroFileId)> + '_ {
+        self.expansions.iter().map(|(&a, &b)| (a, b))
+    }
+
     pub fn pat_syntax(&self, pat: PatId) -> Result<PatSource, SyntheticSyntax> {
         self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index 340e95d..82f8939 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -1006,7 +1006,9 @@
             Some((mark, expansion)) => {
                 // Keep collecting even with expansion errors so we can provide completions and
                 // other services in incomplete macro expressions.
-                self.source_map.expansions.insert(macro_call_ptr, self.expander.current_file_id());
+                self.source_map
+                    .expansions
+                    .insert(macro_call_ptr, self.expander.current_file_id().macro_file().unwrap());
                 let prev_ast_id_map = mem::replace(
                     &mut self.ast_id_map,
                     self.db.ast_id_map(self.expander.current_file_id()),
@@ -1869,42 +1871,45 @@
     ) -> ExprId {
         match count {
             Some(FormatCount::Literal(n)) => {
-                match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Is]) {
-                    Some(count_is) => {
-                        let count_is = self.alloc_expr_desugared(Expr::Path(count_is));
-                        let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
-                            *n as u128,
-                            Some(BuiltinUint::Usize),
-                        )));
-                        self.alloc_expr_desugared(Expr::Call {
-                            callee: count_is,
-                            args: Box::new([args]),
-                            is_assignee_expr: false,
-                        })
-                    }
-                    None => self.missing_expr(),
-                }
+                let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+                    *n as u128,
+                    Some(BuiltinUint::Usize),
+                )));
+                let count_is =
+                    match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Is]) {
+                        Some(count_is) => self.alloc_expr_desugared(Expr::Path(count_is)),
+                        None => self.missing_expr(),
+                    };
+                self.alloc_expr_desugared(Expr::Call {
+                    callee: count_is,
+                    args: Box::new([args]),
+                    is_assignee_expr: false,
+                })
             }
             Some(FormatCount::Argument(arg)) => {
                 if let Ok(arg_index) = arg.index {
                     let (i, _) = argmap.insert_full((arg_index, ArgumentType::Usize));
 
-                    match LangItem::FormatCount.ty_rel_path(self.db, self.krate, name![Param]) {
-                        Some(count_param) => {
-                            let count_param = self.alloc_expr_desugared(Expr::Path(count_param));
-                            let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
-                                i as u128,
-                                Some(BuiltinUint::Usize),
-                            )));
-                            self.alloc_expr_desugared(Expr::Call {
-                                callee: count_param,
-                                args: Box::new([args]),
-                                is_assignee_expr: false,
-                            })
-                        }
+                    let args = self.alloc_expr_desugared(Expr::Literal(Literal::Uint(
+                        i as u128,
+                        Some(BuiltinUint::Usize),
+                    )));
+                    let count_param = match LangItem::FormatCount.ty_rel_path(
+                        self.db,
+                        self.krate,
+                        name![Param],
+                    ) {
+                        Some(count_param) => self.alloc_expr_desugared(Expr::Path(count_param)),
                         None => self.missing_expr(),
-                    }
+                    };
+                    self.alloc_expr_desugared(Expr::Call {
+                        callee: count_param,
+                        args: Box::new([args]),
+                        is_assignee_expr: false,
+                    })
                 } else {
+                    // FIXME: This drops arg causing it to potentially not be resolved/type checked
+                    // when typing?
                     self.missing_expr()
                 }
             }
@@ -1925,7 +1930,8 @@
     fn make_argument(&mut self, arg: ExprId, ty: ArgumentType) -> ExprId {
         use ArgumentType::*;
         use FormatTrait::*;
-        match LangItem::FormatArgument.ty_rel_path(
+
+        let new_fn = match LangItem::FormatArgument.ty_rel_path(
             self.db,
             self.krate,
             match ty {
@@ -1941,16 +1947,14 @@
                 Usize => name![from_usize],
             },
         ) {
-            Some(new_fn) => {
-                let new_fn = self.alloc_expr_desugared(Expr::Path(new_fn));
-                self.alloc_expr_desugared(Expr::Call {
-                    callee: new_fn,
-                    args: Box::new([arg]),
-                    is_assignee_expr: false,
-                })
-            }
+            Some(new_fn) => self.alloc_expr_desugared(Expr::Path(new_fn)),
             None => self.missing_expr(),
-        }
+        };
+        self.alloc_expr_desugared(Expr::Call {
+            callee: new_fn,
+            args: Box::new([arg]),
+            is_assignee_expr: false,
+        })
     }
     // endregion: format
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
index 0020e4e..fd68523 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
@@ -7,7 +7,7 @@
     body::Body,
     db::DefDatabase,
     hir::{Binding, BindingId, Expr, ExprId, LabelId, Pat, PatId, Statement},
-    BlockId, DefWithBodyId,
+    BlockId, ConstBlockId, DefWithBodyId,
 };
 
 pub type ScopeId = Idx<ScopeData>;
@@ -46,7 +46,9 @@
 impl ExprScopes {
     pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc<ExprScopes> {
         let body = db.body(def);
-        let mut scopes = ExprScopes::new(&body);
+        let mut scopes = ExprScopes::new(&body, |const_block| {
+            db.lookup_intern_anonymous_const(const_block).root
+        });
         scopes.shrink_to_fit();
         Arc::new(scopes)
     }
@@ -89,7 +91,10 @@
 }
 
 impl ExprScopes {
-    fn new(body: &Body) -> ExprScopes {
+    fn new(
+        body: &Body,
+        resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
+    ) -> ExprScopes {
         let mut scopes = ExprScopes {
             scopes: Arena::default(),
             scope_entries: Arena::default(),
@@ -100,7 +105,7 @@
             scopes.add_bindings(body, root, self_param);
         }
         scopes.add_params_bindings(body, root, &body.params);
-        compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root);
+        compute_expr_scopes(body.body_expr, body, &mut scopes, &mut root, resolve_const_block);
         scopes
     }
 
@@ -183,35 +188,46 @@
     body: &Body,
     scopes: &mut ExprScopes,
     scope: &mut ScopeId,
+    resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
 ) {
     for stmt in statements {
         match stmt {
             Statement::Let { pat, initializer, else_branch, .. } => {
                 if let Some(expr) = initializer {
-                    compute_expr_scopes(*expr, body, scopes, scope);
+                    compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
                 }
                 if let Some(expr) = else_branch {
-                    compute_expr_scopes(*expr, body, scopes, scope);
+                    compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
                 }
 
                 *scope = scopes.new_scope(*scope);
                 scopes.add_pat_bindings(body, *scope, *pat);
             }
             Statement::Expr { expr, .. } => {
-                compute_expr_scopes(*expr, body, scopes, scope);
+                compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
             }
             Statement::Item => (),
         }
     }
     if let Some(expr) = tail {
-        compute_expr_scopes(expr, body, scopes, scope);
+        compute_expr_scopes(expr, body, scopes, scope, resolve_const_block);
     }
 }
 
-fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: &mut ScopeId) {
+fn compute_expr_scopes(
+    expr: ExprId,
+    body: &Body,
+    scopes: &mut ExprScopes,
+    scope: &mut ScopeId,
+    resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
+) {
     let make_label =
         |label: &Option<LabelId>| label.map(|label| (label, body.labels[label].name.clone()));
 
+    let compute_expr_scopes = |scopes: &mut ExprScopes, expr: ExprId, scope: &mut ScopeId| {
+        compute_expr_scopes(expr, body, scopes, scope, resolve_const_block)
+    };
+
     scopes.set_scope(expr, *scope);
     match &body[expr] {
         Expr::Block { statements, tail, id, label } => {
@@ -219,53 +235,54 @@
             // Overwrite the old scope for the block expr, so that every block scope can be found
             // via the block itself (important for blocks that only contain items, no expressions).
             scopes.set_scope(expr, scope);
-            compute_block_scopes(statements, *tail, body, scopes, &mut scope);
+            compute_block_scopes(statements, *tail, body, scopes, &mut scope, resolve_const_block);
         }
-        Expr::Const(_) => {
-            // FIXME: This is broken.
+        Expr::Const(id) => {
+            let mut scope = scopes.root_scope();
+            compute_expr_scopes(scopes, resolve_const_block(*id), &mut scope);
         }
         Expr::Unsafe { id, statements, tail } | Expr::Async { id, statements, tail } => {
             let mut scope = scopes.new_block_scope(*scope, *id, None);
             // Overwrite the old scope for the block expr, so that every block scope can be found
             // via the block itself (important for blocks that only contain items, no expressions).
             scopes.set_scope(expr, scope);
-            compute_block_scopes(statements, *tail, body, scopes, &mut scope);
+            compute_block_scopes(statements, *tail, body, scopes, &mut scope, resolve_const_block);
         }
         Expr::Loop { body: body_expr, label } => {
             let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
-            compute_expr_scopes(*body_expr, body, scopes, &mut scope);
+            compute_expr_scopes(scopes, *body_expr, &mut scope);
         }
         Expr::Closure { args, body: body_expr, .. } => {
             let mut scope = scopes.new_scope(*scope);
             scopes.add_params_bindings(body, scope, args);
-            compute_expr_scopes(*body_expr, body, scopes, &mut scope);
+            compute_expr_scopes(scopes, *body_expr, &mut scope);
         }
         Expr::Match { expr, arms } => {
-            compute_expr_scopes(*expr, body, scopes, scope);
+            compute_expr_scopes(scopes, *expr, scope);
             for arm in arms.iter() {
                 let mut scope = scopes.new_scope(*scope);
                 scopes.add_pat_bindings(body, scope, arm.pat);
                 if let Some(guard) = arm.guard {
                     scope = scopes.new_scope(scope);
-                    compute_expr_scopes(guard, body, scopes, &mut scope);
+                    compute_expr_scopes(scopes, guard, &mut scope);
                 }
-                compute_expr_scopes(arm.expr, body, scopes, &mut scope);
+                compute_expr_scopes(scopes, arm.expr, &mut scope);
             }
         }
         &Expr::If { condition, then_branch, else_branch } => {
             let mut then_branch_scope = scopes.new_scope(*scope);
-            compute_expr_scopes(condition, body, scopes, &mut then_branch_scope);
-            compute_expr_scopes(then_branch, body, scopes, &mut then_branch_scope);
+            compute_expr_scopes(scopes, condition, &mut then_branch_scope);
+            compute_expr_scopes(scopes, then_branch, &mut then_branch_scope);
             if let Some(else_branch) = else_branch {
-                compute_expr_scopes(else_branch, body, scopes, scope);
+                compute_expr_scopes(scopes, else_branch, scope);
             }
         }
         &Expr::Let { pat, expr } => {
-            compute_expr_scopes(expr, body, scopes, scope);
+            compute_expr_scopes(scopes, expr, scope);
             *scope = scopes.new_scope(*scope);
             scopes.add_pat_bindings(body, *scope, pat);
         }
-        e => e.walk_child_exprs(|e| compute_expr_scopes(e, body, scopes, scope)),
+        e => e.walk_child_exprs(|e| compute_expr_scopes(scopes, e, scope)),
     };
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
index a27ffe2..4c8a54f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
@@ -318,18 +318,20 @@
 
     expect![[r#"
         fn f() {
-            $crate::panicking::panic_fmt(
-                builtin#lang(Arguments::new_v1_formatted)(
-                    &[
-                        "cc",
-                    ],
-                    &[],
-                    &[],
-                    unsafe {
-                        builtin#lang(UnsafeArg::new)()
-                    },
-                ),
-            );
+            {
+                $crate::panicking::panic_fmt(
+                    builtin#lang(Arguments::new_v1_formatted)(
+                        &[
+                            "cc",
+                        ],
+                        &[],
+                        &[],
+                        unsafe {
+                            builtin#lang(UnsafeArg::new)()
+                        },
+                    ),
+                );
+            };
         }"#]]
     .assert_eq(&body.pretty_print(&db, def))
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index e3d750d3..51a4dd6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -229,7 +229,7 @@
     /// method calls to this trait's methods when the receiver is an array and the crate edition is
     /// 2015 or 2018.
     // box it as the vec is usually empty anyways
-    pub attribute_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
+    pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
 }
 
 impl TraitData {
@@ -258,12 +258,12 @@
         let mut collector =
             AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr));
         collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items);
-        let (items, attribute_calls, diagnostics) = collector.finish();
+        let (items, macro_calls, diagnostics) = collector.finish();
 
         (
             Arc::new(TraitData {
                 name,
-                attribute_calls,
+                macro_calls,
                 items,
                 is_auto,
                 is_unsafe,
@@ -298,7 +298,7 @@
     }
 
     pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
-        self.attribute_calls.iter().flat_map(|it| it.iter()).copied()
+        self.macro_calls.iter().flat_map(|it| it.iter()).copied()
     }
 }
 
@@ -319,7 +319,7 @@
     }
 }
 
-#[derive(Debug, Clone, PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq)]
 pub struct ImplData {
     pub target_trait: Option<Interned<TraitRef>>,
     pub self_ty: Interned<TypeRef>,
@@ -327,7 +327,7 @@
     pub is_negative: bool,
     pub is_unsafe: bool,
     // box it as the vec is usually empty anyways
-    pub attribute_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
+    pub macro_calls: Option<Box<Vec<(AstId<ast::Item>, MacroCallId)>>>,
 }
 
 impl ImplData {
@@ -354,7 +354,7 @@
             AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::ImplId(id));
         collector.collect(&item_tree, tree_id.tree_id(), &impl_def.items);
 
-        let (items, attribute_calls, diagnostics) = collector.finish();
+        let (items, macro_calls, diagnostics) = collector.finish();
         let items = items.into_iter().map(|(_, item)| item).collect();
 
         (
@@ -364,14 +364,14 @@
                 items,
                 is_negative,
                 is_unsafe,
-                attribute_calls,
+                macro_calls,
             }),
             DefDiagnostics::new(diagnostics),
         )
     }
 
     pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
-        self.attribute_calls.iter().flat_map(|it| it.iter()).copied()
+        self.macro_calls.iter().flat_map(|it| it.iter()).copied()
     }
 }
 
@@ -573,7 +573,7 @@
     expander: Expander,
 
     items: Vec<(Name, AssocItemId)>,
-    attr_calls: Vec<(AstId<ast::Item>, MacroCallId)>,
+    macro_calls: Vec<(AstId<ast::Item>, MacroCallId)>,
 }
 
 impl<'a> AssocItemCollector<'a> {
@@ -590,7 +590,7 @@
             container,
             expander: Expander::new(db, file_id, module_id),
             items: Vec::new(),
-            attr_calls: Vec::new(),
+            macro_calls: Vec::new(),
             diagnostics: Vec::new(),
         }
     }
@@ -604,7 +604,7 @@
     ) {
         (
             self.items,
-            if self.attr_calls.is_empty() { None } else { Some(Box::new(self.attr_calls)) },
+            if self.macro_calls.is_empty() { None } else { Some(Box::new(self.macro_calls)) },
             self.diagnostics,
         )
     }
@@ -662,11 +662,11 @@
                             }
                         }
 
-                        self.attr_calls.push((ast_id, call_id));
+                        self.macro_calls.push((ast_id, call_id));
 
                         let res =
                             self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id);
-                        self.collect_macro_items(res, &|| loc.kind.clone());
+                        self.collect_macro_items(res);
                         continue 'items;
                     }
                     Ok(_) => (),
@@ -698,24 +698,22 @@
         match item {
             AssocItem::Function(id) => {
                 let item = &item_tree[id];
-
                 let def =
                     FunctionLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
                 self.items.push((item.name.clone(), def.into()));
             }
+            AssocItem::TypeAlias(id) => {
+                let item = &item_tree[id];
+                let def =
+                    TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
+                self.items.push((item.name.clone(), def.into()));
+            }
             AssocItem::Const(id) => {
                 let item = &item_tree[id];
                 let Some(name) = item.name.clone() else { return };
                 let def = ConstLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
                 self.items.push((name, def.into()));
             }
-            AssocItem::TypeAlias(id) => {
-                let item = &item_tree[id];
-
-                let def =
-                    TypeAliasLoc { container, id: ItemTreeId::new(tree_id, id) }.intern(self.db);
-                self.items.push((item.name.clone(), def.into()));
-            }
             AssocItem::MacroCall(call) => {
                 let file_id = self.expander.current_file_id();
                 let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call];
@@ -745,11 +743,8 @@
                     Ok(Some(call_id)) => {
                         let res =
                             self.expander.enter_expand_id::<ast::MacroItems>(self.db, call_id);
-                        self.collect_macro_items(res, &|| hir_expand::MacroCallKind::FnLike {
-                            ast_id: InFile::new(file_id, ast_id),
-                            expand_to: hir_expand::ExpandTo::Items,
-                            eager: None,
-                        });
+                        self.macro_calls.push((InFile::new(file_id, ast_id.upcast()), call_id));
+                        self.collect_macro_items(res);
                     }
                     Ok(None) => (),
                     Err(_) => {
@@ -768,39 +763,8 @@
         }
     }
 
-    fn collect_macro_items(
-        &mut self,
-        ExpandResult { value, err }: ExpandResult<Option<(Mark, Parse<ast::MacroItems>)>>,
-        error_call_kind: &dyn Fn() -> hir_expand::MacroCallKind,
-    ) {
-        let Some((mark, parse)) = value else { return };
-
-        if let Some(err) = err {
-            let diag = match err {
-                // why is this reported here?
-                hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
-                    DefDiagnostic::unresolved_proc_macro(
-                        self.module_id.local_id,
-                        error_call_kind(),
-                        krate,
-                    )
-                }
-                _ => DefDiagnostic::macro_error(
-                    self.module_id.local_id,
-                    error_call_kind(),
-                    err.to_string(),
-                ),
-            };
-            self.diagnostics.push(diag);
-        }
-        let errors = parse.errors();
-        if !errors.is_empty() {
-            self.diagnostics.push(DefDiagnostic::macro_expansion_parse_error(
-                self.module_id.local_id,
-                error_call_kind(),
-                errors.into_boxed_slice(),
-            ));
-        }
+    fn collect_macro_items(&mut self, res: ExpandResult<Option<(Mark, Parse<ast::MacroItems>)>>) {
+        let Some((mark, _parse)) = res.value else { return };
 
         let tree_id = item_tree::TreeId::new(self.expander.current_file_id(), None);
         let item_tree = tree_id.item_tree(self.db);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index bf728a7..4e57845 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -1177,6 +1177,8 @@
 //- /main.rs crate:main deps:alloc,std
 #![no_std]
 
+extern crate alloc;
+
 $0
 
 //- /std.rs crate:std deps:alloc
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index acc60e1..10a1d65 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -20,7 +20,7 @@
 use crate::{
     db::DefDatabase,
     expander::Expander,
-    item_tree::{GenericsItemTreeNode, ItemTree},
+    item_tree::{AttrOwner, FileItemTreeId, GenericModItem, GenericsItemTreeNode, ItemTree},
     lower::LowerCtx,
     nameres::{DefMap, MacroSubNs},
     type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
@@ -339,6 +339,7 @@
         target: Either<TypeRef, LifetimeRef>,
     ) {
         let bound = TypeBound::from_ast(lower_ctx, bound);
+        self.fill_impl_trait_bounds(lower_ctx.take_impl_traits_bounds());
         let predicate = match (target, bound) {
             (Either::Left(type_ref), bound) => match hrtb_lifetimes {
                 Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
@@ -359,7 +360,24 @@
         self.where_predicates.push(predicate);
     }
 
-    pub(crate) fn fill_implicit_impl_trait_args(
+    fn fill_impl_trait_bounds(&mut self, impl_bounds: Vec<Vec<Interned<TypeBound>>>) {
+        for bounds in impl_bounds {
+            let param = TypeParamData {
+                name: None,
+                default: None,
+                provenance: TypeParamProvenance::ArgumentImplTrait,
+            };
+            let param_id = self.type_or_consts.alloc(param.into());
+            for bound in bounds {
+                self.where_predicates.push(WherePredicate::TypeBound {
+                    target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
+                    bound,
+                });
+            }
+        }
+    }
+
+    fn fill_implicit_impl_trait_args(
         &mut self,
         db: &dyn DefDatabase,
         exp: &mut Lazy<(Arc<DefMap>, Expander), impl FnOnce() -> (Arc<DefMap>, Expander)>,
@@ -456,56 +474,67 @@
         let cfg_options = &cfg_options[krate].cfg_options;
 
         // Returns the generic parameters that are enabled under the current `#[cfg]` options
-        let enabled_params = |params: &Interned<GenericParams>, item_tree: &ItemTree| {
-            let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
+        let enabled_params =
+            |params: &Interned<GenericParams>, item_tree: &ItemTree, parent: GenericModItem| {
+                let enabled = |param| item_tree.attrs(db, krate, param).is_cfg_enabled(cfg_options);
+                let attr_owner_ct = |param| AttrOwner::TypeOrConstParamData(parent, param);
+                let attr_owner_lt = |param| AttrOwner::LifetimeParamData(parent, param);
 
-            // In the common case, no parameters will by disabled by `#[cfg]` attributes.
-            // Therefore, make a first pass to check if all parameters are enabled and, if so,
-            // clone the `Interned<GenericParams>` instead of recreating an identical copy.
-            let all_type_or_consts_enabled =
-                params.type_or_consts.iter().all(|(idx, _)| enabled(idx.into()));
-            let all_lifetimes_enabled = params.lifetimes.iter().all(|(idx, _)| enabled(idx.into()));
+                // In the common case, no parameters will by disabled by `#[cfg]` attributes.
+                // Therefore, make a first pass to check if all parameters are enabled and, if so,
+                // clone the `Interned<GenericParams>` instead of recreating an identical copy.
+                let all_type_or_consts_enabled =
+                    params.type_or_consts.iter().all(|(idx, _)| enabled(attr_owner_ct(idx)));
+                let all_lifetimes_enabled =
+                    params.lifetimes.iter().all(|(idx, _)| enabled(attr_owner_lt(idx)));
 
-            if all_type_or_consts_enabled && all_lifetimes_enabled {
-                params.clone()
-            } else {
-                Interned::new(GenericParams {
-                    type_or_consts: all_type_or_consts_enabled
-                        .then(|| params.type_or_consts.clone())
-                        .unwrap_or_else(|| {
-                            params
-                                .type_or_consts
-                                .iter()
-                                .filter(|(idx, _)| enabled((*idx).into()))
-                                .map(|(_, param)| param.clone())
-                                .collect()
-                        }),
-                    lifetimes: all_lifetimes_enabled
-                        .then(|| params.lifetimes.clone())
-                        .unwrap_or_else(|| {
-                            params
-                                .lifetimes
-                                .iter()
-                                .filter(|(idx, _)| enabled((*idx).into()))
-                                .map(|(_, param)| param.clone())
-                                .collect()
-                        }),
-                    where_predicates: params.where_predicates.clone(),
-                })
-            }
-        };
+                if all_type_or_consts_enabled && all_lifetimes_enabled {
+                    params.clone()
+                } else {
+                    Interned::new(GenericParams {
+                        type_or_consts: all_type_or_consts_enabled
+                            .then(|| params.type_or_consts.clone())
+                            .unwrap_or_else(|| {
+                                params
+                                    .type_or_consts
+                                    .iter()
+                                    .filter(|&(idx, _)| enabled(attr_owner_ct(idx)))
+                                    .map(|(_, param)| param.clone())
+                                    .collect()
+                            }),
+                        lifetimes: all_lifetimes_enabled
+                            .then(|| params.lifetimes.clone())
+                            .unwrap_or_else(|| {
+                                params
+                                    .lifetimes
+                                    .iter()
+                                    .filter(|&(idx, _)| enabled(attr_owner_lt(idx)))
+                                    .map(|(_, param)| param.clone())
+                                    .collect()
+                            }),
+                        where_predicates: params.where_predicates.clone(),
+                    })
+                }
+            };
         fn id_to_generics<Id: GenericsItemTreeNode>(
             db: &dyn DefDatabase,
             id: impl for<'db> Lookup<
                 Database<'db> = dyn DefDatabase + 'db,
                 Data = impl ItemTreeLoc<Id = Id>,
             >,
-            enabled_params: impl Fn(&Interned<GenericParams>, &ItemTree) -> Interned<GenericParams>,
-        ) -> Interned<GenericParams> {
+            enabled_params: impl Fn(
+                &Interned<GenericParams>,
+                &ItemTree,
+                GenericModItem,
+            ) -> Interned<GenericParams>,
+        ) -> Interned<GenericParams>
+        where
+            FileItemTreeId<Id>: Into<GenericModItem>,
+        {
             let id = id.lookup(db).item_tree_id();
             let tree = id.item_tree(db);
             let item = &tree[id.value];
-            enabled_params(item.generic_params(), &tree)
+            enabled_params(item.generic_params(), &tree, id.value.into())
         }
 
         match def {
@@ -514,7 +543,8 @@
                 let tree = loc.id.item_tree(db);
                 let item = &tree[loc.id.value];
 
-                let enabled_params = enabled_params(&item.explicit_generic_params, &tree);
+                let enabled_params =
+                    enabled_params(&item.explicit_generic_params, &tree, loc.id.value.into());
 
                 let module = loc.container.module(db);
                 let func_data = db.function_data(id);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
index ac0caaf..2f7ebbf 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -136,15 +136,15 @@
                 Literal::Float(FloatTypeWrapper::new(lit.value().unwrap_or(Default::default())), ty)
             }
             LiteralKind::ByteString(bs) => {
-                let text = bs.value().map(Box::from).unwrap_or_else(Default::default);
+                let text = bs.value().map_or_else(|_| Default::default(), Box::from);
                 Literal::ByteString(text)
             }
             LiteralKind::String(s) => {
-                let text = s.value().map(Box::from).unwrap_or_else(Default::default);
+                let text = s.value().map_or_else(|_| Default::default(), Box::from);
                 Literal::String(text)
             }
             LiteralKind::CString(s) => {
-                let text = s.value().map(Box::from).unwrap_or_else(Default::default);
+                let text = s.value().map_or_else(|_| Default::default(), Box::from);
                 Literal::CString(text)
             }
             LiteralKind::Byte(b) => {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index a60b9f9..54cd571 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
@@ -234,6 +234,14 @@
         self.impls.iter().copied()
     }
 
+    pub fn all_macro_calls(&self) -> impl Iterator<Item = MacroCallId> + '_ {
+        self.macro_invocations.values().copied().chain(self.attr_macros.values().copied()).chain(
+            self.derive_macros.values().flat_map(|it| {
+                it.iter().flat_map(|it| it.derive_call_ids.iter().copied().flatten())
+            }),
+        )
+    }
+
     pub(crate) fn modules_in_scope(&self) -> impl Iterator<Item = (ModuleId, Visibility)> + '_ {
         self.types.values().copied().filter_map(|(def, vis, _)| match def {
             ModuleDefId::ModuleId(module) => Some((module, vis)),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index 6104807..acda64c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -29,6 +29,7 @@
 //!
 //! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its
 //! surface syntax.
+#![allow(unexpected_cfgs)]
 
 mod lower;
 mod pretty;
@@ -57,21 +58,21 @@
 use crate::{
     attr::Attrs,
     db::DefDatabase,
-    generics::{GenericParams, LifetimeParamData, TypeOrConstParamData},
+    generics::GenericParams,
     path::{GenericArgs, ImportAlias, ModPath, Path, PathKind},
     type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
     visibility::{RawVisibility, VisibilityExplicitness},
-    BlockId, Lookup,
+    BlockId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup,
 };
 
 #[derive(Copy, Clone, Eq, PartialEq)]
 pub struct RawVisibilityId(u32);
 
 impl RawVisibilityId {
-    pub const PUB: Self = RawVisibilityId(u32::max_value());
-    pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::max_value() - 1);
-    pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::max_value() - 2);
-    pub const PUB_CRATE: Self = RawVisibilityId(u32::max_value() - 3);
+    pub const PUB: Self = RawVisibilityId(u32::MAX);
+    pub const PRIV_IMPLICIT: Self = RawVisibilityId(u32::MAX - 1);
+    pub const PRIV_EXPLICIT: Self = RawVisibilityId(u32::MAX - 2);
+    pub const PUB_CRATE: Self = RawVisibilityId(u32::MAX - 3);
 }
 
 impl fmt::Debug for RawVisibilityId {
@@ -293,8 +294,8 @@
     Variant(FileItemTreeId<Variant>),
     Field(Idx<Field>),
     Param(Idx<Param>),
-    TypeOrConstParamData(Idx<TypeOrConstParamData>),
-    LifetimeParamData(Idx<LifetimeParamData>),
+    TypeOrConstParamData(GenericModItem, LocalTypeOrConstParamId),
+    LifetimeParamData(GenericModItem, LocalLifetimeParamId),
 }
 
 macro_rules! from_attrs {
@@ -314,8 +315,6 @@
     Variant(FileItemTreeId<Variant>),
     Field(Idx<Field>),
     Param(Idx<Param>),
-    TypeOrConstParamData(Idx<TypeOrConstParamData>),
-    LifetimeParamData(Idx<LifetimeParamData>),
 );
 
 /// Trait implemented by all nodes in the item tree.
@@ -465,12 +464,49 @@
             )+
         }
 
+        #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
+        pub enum GenericModItem {
+            $(
+                $(
+                    #[cfg_attr(ignore_fragment, $generic_params)]
+                    $typ(FileItemTreeId<$typ>),
+                )?
+            )+
+        }
+
+        impl From<GenericModItem> for ModItem {
+            fn from(id: GenericModItem) -> ModItem {
+                match id {
+                    $(
+                        $(
+                            #[cfg_attr(ignore_fragment, $generic_params)]
+                            GenericModItem::$typ(id) => ModItem::$typ(id),
+                        )?
+                    )+
+                }
+            }
+        }
+
+        impl From<GenericModItem> for AttrOwner {
+            fn from(t: GenericModItem) -> AttrOwner {
+                AttrOwner::ModItem(t.into())
+            }
+        }
+
         $(
             impl From<FileItemTreeId<$typ>> for ModItem {
                 fn from(id: FileItemTreeId<$typ>) -> ModItem {
                     ModItem::$typ(id)
                 }
             }
+            $(
+                #[cfg_attr(ignore_fragment, $generic_params)]
+                impl From<FileItemTreeId<$typ>> for GenericModItem {
+                    fn from(id: FileItemTreeId<$typ>) -> GenericModItem {
+                        GenericModItem::$typ(id)
+                    }
+                }
+            )?
         )+
 
         $(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index 4b5ef56..199b8da 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -4,6 +4,7 @@
 
 use hir_expand::{mod_path::path, name, name::AsName, span_map::SpanMapRef, HirFileId};
 use la_arena::Arena;
+use rustc_hash::FxHashMap;
 use span::{AstIdMap, SyntaxContextId};
 use syntax::{
     ast::{self, HasModuleItem, HasName, HasTypeBounds, IsString},
@@ -16,11 +17,11 @@
     generics::{GenericParams, GenericParamsCollector, TypeParamData, TypeParamProvenance},
     item_tree::{
         AssocItem, AttrOwner, Const, Either, Enum, ExternBlock, ExternCrate, Field, FieldAstId,
-        Fields, FileItemTreeId, FnFlags, Function, GenericArgs, Idx, IdxRange, Impl, ImportAlias,
-        Interned, ItemTree, ItemTreeData, ItemTreeNode, Macro2, MacroCall, MacroRules, Mod,
-        ModItem, ModKind, ModPath, Mutability, Name, Param, ParamAstId, Path, Range, RawAttrs,
-        RawIdx, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias, TypeAlias, Union,
-        Use, UseTree, UseTreeKind, Variant,
+        Fields, FileItemTreeId, FnFlags, Function, GenericArgs, GenericModItem, Idx, IdxRange,
+        Impl, ImportAlias, Interned, ItemTree, ItemTreeData, ItemTreeNode, Macro2, MacroCall,
+        MacroRules, Mod, ModItem, ModKind, ModPath, Mutability, Name, Param, ParamAstId, Path,
+        Range, RawAttrs, RawIdx, RawVisibilityId, Static, Struct, StructKind, Trait, TraitAlias,
+        TypeAlias, Union, Use, UseTree, UseTreeKind, Variant,
     },
     path::AssociatedTypeBinding,
     type_ref::{LifetimeRef, TraitBoundModifier, TraitRef, TypeBound, TypeRef},
@@ -36,6 +37,8 @@
     db: &'a dyn DefDatabase,
     tree: ItemTree,
     source_ast_id_map: Arc<AstIdMap>,
+    generic_param_attr_buffer:
+        FxHashMap<Either<LocalTypeOrConstParamId, LocalLifetimeParamId>, RawAttrs>,
     body_ctx: crate::lower::LowerCtx<'a>,
 }
 
@@ -44,6 +47,7 @@
         Self {
             db,
             tree: ItemTree::default(),
+            generic_param_attr_buffer: FxHashMap::default(),
             source_ast_id_map: db.ast_id_map(file),
             body_ctx: crate::lower::LowerCtx::new(db, file),
         }
@@ -56,6 +60,7 @@
     pub(super) fn lower_module_items(mut self, item_owner: &dyn HasModuleItem) -> ItemTree {
         self.tree.top_level =
             item_owner.items().flat_map(|item| self.lower_mod_item(&item)).collect();
+        assert!(self.generic_param_attr_buffer.is_empty());
         self.tree
     }
 
@@ -89,6 +94,7 @@
             }
         }
 
+        assert!(self.generic_param_attr_buffer.is_empty());
         self.tree
     }
 
@@ -117,6 +123,7 @@
             }
         }
 
+        assert!(self.generic_param_attr_buffer.is_empty());
         self.tree
     }
 
@@ -185,10 +192,12 @@
         let visibility = self.lower_visibility(strukt);
         let name = strukt.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(strukt);
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt);
         let fields = self.lower_fields(&strukt.kind());
+        let generic_params = self.lower_generic_params(HasImplicitSelf::No, strukt);
         let res = Struct { name, visibility, generic_params, fields, ast_id };
-        Some(id(self.data().structs.alloc(res)))
+        let id = id(self.data().structs.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_fields(&mut self, strukt_kind: &ast::StructKind) -> Fields {
@@ -252,28 +261,32 @@
         let visibility = self.lower_visibility(union);
         let name = union.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(union);
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, union);
         let fields = match union.record_field_list() {
             Some(record_field_list) => self.lower_fields(&StructKind::Record(record_field_list)),
             None => Fields::Record(IdxRange::new(self.next_field_idx()..self.next_field_idx())),
         };
+        let generic_params = self.lower_generic_params(HasImplicitSelf::No, union);
         let res = Union { name, visibility, generic_params, fields, ast_id };
-        Some(id(self.data().unions.alloc(res)))
+        let id = id(self.data().unions.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_enum(&mut self, enum_: &ast::Enum) -> Option<FileItemTreeId<Enum>> {
         let visibility = self.lower_visibility(enum_);
         let name = enum_.name()?.as_name();
         let ast_id = self.source_ast_id_map.ast_id(enum_);
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
         let variants = match &enum_.variant_list() {
             Some(variant_list) => self.lower_variants(variant_list),
             None => {
                 FileItemTreeId(self.next_variant_idx())..FileItemTreeId(self.next_variant_idx())
             }
         };
+        let generic_params = self.lower_generic_params(HasImplicitSelf::No, enum_);
         let res = Enum { name, visibility, generic_params, variants, ast_id };
-        Some(id(self.data().enums.alloc(res)))
+        let id = id(self.data().enums.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_variants(&mut self, variants: &ast::VariantList) -> Range<FileItemTreeId<Variant>> {
@@ -414,7 +427,9 @@
             flags,
         };
 
-        Some(id(self.data().functions.alloc(res)))
+        let id = id(self.data().functions.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_type_alias(
@@ -428,7 +443,9 @@
         let ast_id = self.source_ast_id_map.ast_id(type_alias);
         let generic_params = self.lower_generic_params(HasImplicitSelf::No, type_alias);
         let res = TypeAlias { name, visibility, bounds, generic_params, type_ref, ast_id };
-        Some(id(self.data().type_aliases.alloc(res)))
+        let id = id(self.data().type_aliases.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_static(&mut self, static_: &ast::Static) -> Option<FileItemTreeId<Static>> {
@@ -475,8 +492,6 @@
         let name = trait_def.name()?.as_name();
         let visibility = self.lower_visibility(trait_def);
         let ast_id = self.source_ast_id_map.ast_id(trait_def);
-        let generic_params =
-            self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
         let is_auto = trait_def.auto_token().is_some();
         let is_unsafe = trait_def.unsafe_token().is_some();
 
@@ -487,8 +502,12 @@
             .filter_map(|item_node| self.lower_assoc_item(&item_node))
             .collect();
 
+        let generic_params =
+            self.lower_generic_params(HasImplicitSelf::Yes(trait_def.type_bound_list()), trait_def);
         let def = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id };
-        Some(id(self.data().traits.alloc(def)))
+        let id = id(self.data().traits.alloc(def));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_trait_alias(
@@ -504,19 +523,18 @@
         );
 
         let alias = TraitAlias { name, visibility, generic_params, ast_id };
-        Some(id(self.data().trait_aliases.alloc(alias)))
+        let id = id(self.data().trait_aliases.alloc(alias));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
         let ast_id = self.source_ast_id_map.ast_id(impl_def);
-        // Note that trait impls don't get implicit `Self` unlike traits, because here they are a
-        // type alias rather than a type parameter, so this is handled by the resolver.
-        let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def);
         // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
         // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
         // equals itself.
-        let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
         let self_ty = self.lower_type_ref(&impl_def.self_ty()?);
+        let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
         let is_negative = impl_def.excl_token().is_some();
         let is_unsafe = impl_def.unsafe_token().is_some();
 
@@ -527,9 +545,14 @@
             .flat_map(|it| it.assoc_items())
             .filter_map(|item| self.lower_assoc_item(&item))
             .collect();
+        // Note that trait impls don't get implicit `Self` unlike traits, because here they are a
+        // type alias rather than a type parameter, so this is handled by the resolver.
+        let generic_params = self.lower_generic_params(HasImplicitSelf::No, impl_def);
         let res =
             Impl { generic_params, target_trait, self_ty, is_negative, is_unsafe, items, ast_id };
-        Some(id(self.data().impls.alloc(res)))
+        let id = id(self.data().impls.alloc(res));
+        self.write_generic_params_attributes(id.into());
+        Some(id)
     }
 
     fn lower_use(&mut self, use_item: &ast::Use) -> Option<FileItemTreeId<Use>> {
@@ -616,11 +639,30 @@
         id(self.data().extern_blocks.alloc(res))
     }
 
+    fn write_generic_params_attributes(&mut self, parent: GenericModItem) {
+        self.generic_param_attr_buffer.drain().for_each(|(idx, attrs)| {
+            self.tree.attrs.insert(
+                match idx {
+                    Either::Left(id) => AttrOwner::TypeOrConstParamData(parent, id),
+                    Either::Right(id) => AttrOwner::LifetimeParamData(parent, id),
+                },
+                attrs,
+            );
+        })
+    }
+
     fn lower_generic_params(
         &mut self,
         has_implicit_self: HasImplicitSelf,
         node: &dyn ast::HasGenericParams,
     ) -> Interned<GenericParams> {
+        debug_assert!(self.generic_param_attr_buffer.is_empty(),);
+        let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
+                               param| {
+            let attrs = RawAttrs::new(self.db.upcast(), &param, self.body_ctx.span_map());
+            debug_assert!(self.generic_param_attr_buffer.insert(item, attrs).is_none());
+        };
+        self.body_ctx.take_impl_traits_bounds();
         let mut generics = GenericParamsCollector::default();
 
         if let HasImplicitSelf::Yes(bounds) = has_implicit_self {
@@ -635,28 +677,13 @@
             );
             // add super traits as bounds on Self
             // i.e., `trait Foo: Bar` is equivalent to `trait Foo where Self: Bar`
-            let self_param = TypeRef::Path(name![Self].into());
-            generics.fill_bounds(&self.body_ctx, bounds, Either::Left(self_param));
+            generics.fill_bounds(
+                &self.body_ctx,
+                bounds,
+                Either::Left(TypeRef::Path(name![Self].into())),
+            );
         }
 
-        let add_param_attrs = |item: Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
-                               param| {
-            let attrs = RawAttrs::new(self.db.upcast(), &param, self.body_ctx.span_map());
-            // This is identical to the body of `Ctx::add_attrs()` but we can't call that here
-            // because it requires `&mut self` and the call to `generics.fill()` below also
-            // references `self`.
-            match self.tree.attrs.entry(match item {
-                Either::Right(id) => id.into(),
-                Either::Left(id) => id.into(),
-            }) {
-                Entry::Occupied(mut entry) => {
-                    *entry.get_mut() = entry.get().merge(attrs);
-                }
-                Entry::Vacant(entry) => {
-                    entry.insert(attrs);
-                }
-            }
-        };
         generics.fill(&self.body_ctx, node, add_param_attrs);
 
         Interned::new(generics.finish())
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index cef2a3f..2803678 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -8,8 +8,8 @@
     generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
     item_tree::{
         AttrOwner, Const, DefDatabase, Enum, ExternBlock, ExternCrate, Field, FieldAstId, Fields,
-        FileItemTreeId, FnFlags, Function, GenericParams, Impl, Interned, ItemTree, Macro2,
-        MacroCall, MacroRules, Mod, ModItem, ModKind, Param, ParamAstId, Path, RawAttrs,
+        FileItemTreeId, FnFlags, Function, GenericModItem, GenericParams, Impl, Interned, ItemTree,
+        Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, Param, ParamAstId, Path, RawAttrs,
         RawVisibilityId, Static, Struct, Trait, TraitAlias, TypeAlias, TypeBound, TypeRef, Union,
         Use, UseTree, UseTreeKind, Variant,
     },
@@ -276,7 +276,7 @@
                     w!(self, "extern \"{}\" ", abi);
                 }
                 w!(self, "fn {}", name.display(self.db.upcast()));
-                self.print_generic_params(explicit_generic_params);
+                self.print_generic_params(explicit_generic_params, it.into());
                 w!(self, "(");
                 if !params.is_empty() {
                     self.indented(|this| {
@@ -316,7 +316,7 @@
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "struct {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 self.print_fields_and_where_clause(fields, generic_params);
                 if matches!(fields, Fields::Record(_)) {
                     wln!(self);
@@ -329,7 +329,7 @@
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "union {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 self.print_fields_and_where_clause(fields, generic_params);
                 if matches!(fields, Fields::Record(_)) {
                     wln!(self);
@@ -342,7 +342,7 @@
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "enum {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 self.print_where_clause_and_opening_brace(generic_params);
                 self.indented(|this| {
                     for variant in FileItemTreeId::range_iter(variants.clone()) {
@@ -394,7 +394,7 @@
                     w!(self, "auto ");
                 }
                 w!(self, "trait {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 self.print_where_clause_and_opening_brace(generic_params);
                 self.indented(|this| {
                     for item in &**items {
@@ -408,7 +408,7 @@
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "trait {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 w!(self, " = ");
                 self.print_where_clause(generic_params);
                 w!(self, ";");
@@ -429,7 +429,7 @@
                     w!(self, "unsafe");
                 }
                 w!(self, "impl");
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 w!(self, " ");
                 if *is_negative {
                     w!(self, "!");
@@ -453,7 +453,7 @@
                 self.print_ast_id(ast_id.erase());
                 self.print_visibility(*visibility);
                 w!(self, "type {}", name.display(self.db.upcast()));
-                self.print_generic_params(generic_params);
+                self.print_generic_params(generic_params, it.into());
                 if !bounds.is_empty() {
                     w!(self, ": ");
                     self.print_type_bounds(bounds);
@@ -525,7 +525,7 @@
         print_path(self.db, path, self).unwrap();
     }
 
-    fn print_generic_params(&mut self, params: &GenericParams) {
+    fn print_generic_params(&mut self, params: &GenericParams, parent: GenericModItem) {
         if params.is_empty() {
             return;
         }
@@ -537,7 +537,7 @@
                 w!(self, ", ");
             }
             first = false;
-            self.print_attrs_of(idx, " ");
+            self.print_attrs_of(AttrOwner::LifetimeParamData(parent, idx), " ");
             w!(self, "{}", lt.name.display(self.db.upcast()));
         }
         for (idx, x) in params.type_or_consts.iter() {
@@ -545,7 +545,7 @@
                 w!(self, ", ");
             }
             first = false;
-            self.print_attrs_of(idx, " ");
+            self.print_attrs_of(AttrOwner::TypeOrConstParamData(parent, idx), " ");
             match x {
                 TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
                     Some(name) => w!(self, "{}", name.display(self.db.upcast())),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
index 48da876..79bab11 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/tests.rs
@@ -427,10 +427,18 @@
     check(
         r#"
 struct S<#[cfg(never)] T>;
+struct S<A, B, #[cfg(never)] C>;
+struct S<A, #[cfg(never)] B, C>;
         "#,
         expect![[r#"
             // AstId: 1
             pub(self) struct S<#[cfg(never)] T>;
+
+            // AstId: 2
+            pub(self) struct S<A, B, #[cfg(never)] C>;
+
+            // AstId: 3
+            pub(self) struct S<A, #[cfg(never)] B, C>;
         "#]],
     )
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
index d574d80..ecd8d79 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lower.rs
@@ -1,26 +1,34 @@
 //! Context for lowering paths.
-use std::cell::OnceCell;
+use std::cell::{OnceCell, RefCell};
 
 use hir_expand::{
     span_map::{SpanMap, SpanMapRef},
     AstId, HirFileId, InFile,
 };
+use intern::Interned;
 use span::{AstIdMap, AstIdNode};
 use syntax::ast;
 use triomphe::Arc;
 
-use crate::{db::DefDatabase, path::Path};
+use crate::{db::DefDatabase, path::Path, type_ref::TypeBound};
 
 pub struct LowerCtx<'a> {
     pub db: &'a dyn DefDatabase,
     file_id: HirFileId,
     span_map: OnceCell<SpanMap>,
     ast_id_map: OnceCell<Arc<AstIdMap>>,
+    impl_trait_bounds: RefCell<Vec<Vec<Interned<TypeBound>>>>,
 }
 
 impl<'a> LowerCtx<'a> {
     pub fn new(db: &'a dyn DefDatabase, file_id: HirFileId) -> Self {
-        LowerCtx { db, file_id, span_map: OnceCell::new(), ast_id_map: OnceCell::new() }
+        LowerCtx {
+            db,
+            file_id,
+            span_map: OnceCell::new(),
+            ast_id_map: OnceCell::new(),
+            impl_trait_bounds: RefCell::new(Vec::new()),
+        }
     }
 
     pub fn with_span_map_cell(
@@ -28,7 +36,13 @@
         file_id: HirFileId,
         span_map: OnceCell<SpanMap>,
     ) -> Self {
-        LowerCtx { db, file_id, span_map, ast_id_map: OnceCell::new() }
+        LowerCtx {
+            db,
+            file_id,
+            span_map,
+            ast_id_map: OnceCell::new(),
+            impl_trait_bounds: RefCell::new(Vec::new()),
+        }
     }
 
     pub(crate) fn span_map(&self) -> SpanMapRef<'_> {
@@ -45,4 +59,12 @@
             self.ast_id_map.get_or_init(|| self.db.ast_id_map(self.file_id)).ast_id(item),
         )
     }
+
+    pub fn update_impl_traits_bounds(&self, bounds: Vec<Interned<TypeBound>>) {
+        self.impl_trait_bounds.borrow_mut().push(bounds);
+    }
+
+    pub fn take_impl_traits_bounds(&self) -> Vec<Vec<Interned<TypeBound>>> {
+        self.impl_trait_bounds.take()
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
index a4864c7..6f605c0 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
@@ -186,3 +186,33 @@
 }#0:1@76..77#0#"#]],
     );
 }
+
+#[test]
+fn attribute_macro_doc_desugaring() {
+    check(
+        r#"
+//- proc_macros: identity
+#[proc_macros::identity]
+/// doc string \n with newline
+/**
+     MultiLines Doc
+     MultiLines Doc
+*/
+#[doc = "doc attr"]
+struct S;
+"#,
+        expect![[r##"
+#[proc_macros::identity]
+/// doc string \n with newline
+/**
+     MultiLines Doc
+     MultiLines Doc
+*/
+#[doc = "doc attr"]
+struct S;
+
+#[doc = " doc string \\n with newline"]
+#[doc = "\n     MultiLines Doc\n     MultiLines Doc\n"]
+#[doc = "doc attr"] struct S;"##]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index 0a6cd0f..262bc53 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -5,7 +5,7 @@
 
 use std::{cmp::Ordering, iter, mem, ops::Not};
 
-use base_db::{CrateId, Dependency, FileId};
+use base_db::{CrateId, CrateOrigin, Dependency, FileId, LangCrateOrigin};
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
 use hir_expand::{
@@ -15,15 +15,13 @@
     builtin_fn_macro::find_builtin_macro,
     name::{name, AsName, Name},
     proc_macro::CustomProcMacroExpander,
-    ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallLoc,
-    MacroDefId, MacroDefKind,
+    ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
 };
 use itertools::{izip, Itertools};
 use la_arena::Idx;
 use limit::Limit;
 use rustc_hash::{FxHashMap, FxHashSet};
 use span::{Edition, ErasedFileAstId, FileAstId, Span, SyntaxContextId};
-use stdx::always;
 use syntax::ast;
 use triomphe::Arc;
 
@@ -279,7 +277,8 @@
     fn seed_with_top_level(&mut self) {
         let _p = tracing::span!(tracing::Level::INFO, "seed_with_top_level").entered();
 
-        let file_id = self.db.crate_graph()[self.def_map.krate].root_file_id;
+        let crate_graph = self.db.crate_graph();
+        let file_id = crate_graph[self.def_map.krate].root_file_id;
         let item_tree = self.db.file_item_tree(file_id.into());
         let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
         let crate_data = Arc::get_mut(&mut self.def_map.data).unwrap();
@@ -288,19 +287,14 @@
             crate_data.proc_macro_loading_error = Some(e.clone());
         }
 
-        for (name, dep) in &self.deps {
-            if dep.is_prelude() {
-                crate_data
-                    .extern_prelude
-                    .insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None));
-            }
-        }
+        let mut process = true;
 
         // Process other crate-level attributes.
         for attr in &*attrs {
             if let Some(cfg) = attr.cfg() {
                 if self.cfg_options.check(&cfg) == Some(false) {
-                    return;
+                    process = false;
+                    break;
                 }
             }
             let Some(attr_name) = attr.path.as_ident() else { continue };
@@ -350,9 +344,38 @@
             }
         }
 
-        crate_data.shrink_to_fit();
+        for (name, dep) in &self.deps {
+            if dep.is_prelude() {
+                // This is a bit confusing but the gist is that `no_core` and `no_std` remove the
+                // sysroot dependence on `core` and `std` respectively. Our `CrateGraph` is eagerly
+                // constructed with them in place no matter what though, since at that point we
+                // don't do pre-configured attribute resolution yet.
+                // So here check if we are no_core / no_std and we are trying to add the
+                // corresponding dep from the sysroot
+                let skip = match crate_graph[dep.crate_id].origin {
+                    CrateOrigin::Lang(LangCrateOrigin::Core) => {
+                        crate_data.no_core && dep.is_sysroot()
+                    }
+                    CrateOrigin::Lang(LangCrateOrigin::Std) => {
+                        crate_data.no_std && dep.is_sysroot()
+                    }
+                    _ => false,
+                };
+                if skip {
+                    continue;
+                }
+                crate_data
+                    .extern_prelude
+                    .insert(name.clone(), (CrateRootModuleId { krate: dep.crate_id }, None));
+            }
+        }
+
         self.inject_prelude();
 
+        if !process {
+            return;
+        }
+
         ModCollector {
             def_collector: self,
             macro_depth: 0,
@@ -362,6 +385,7 @@
             mod_dir: ModDir::root(),
         }
         .collect_in_top_module(item_tree.top_level_items());
+        Arc::get_mut(&mut self.def_map.data).unwrap().shrink_to_fit();
     }
 
     fn seed_with_inner(&mut self, tree_id: TreeId) {
@@ -519,15 +543,12 @@
 
         let krate = if self.def_map.data.no_std {
             name![core]
+        } else if self.def_map.extern_prelude().any(|(name, _)| *name == name![std]) {
+            name![std]
         } else {
-            let std = name![std];
-            if self.def_map.extern_prelude().any(|(name, _)| *name == std) {
-                std
-            } else {
-                // If `std` does not exist for some reason, fall back to core. This mostly helps
-                // keep r-a's own tests minimal.
-                name![core]
-            }
+            // If `std` does not exist for some reason, fall back to core. This mostly helps
+            // keep r-a's own tests minimal.
+            name![core]
         };
 
         let edition = match self.def_map.data.edition {
@@ -1389,31 +1410,6 @@
         }
         let file_id = macro_call_id.as_file();
 
-        // First, fetch the raw expansion result for purposes of error reporting. This goes through
-        // `parse_macro_expansion_error` to avoid depending on the full expansion result (to improve
-        // incrementality).
-        // FIXME: This kind of error fetching feels a bit odd?
-        let ExpandResult { value: errors, err } =
-            self.db.parse_macro_expansion_error(macro_call_id);
-        if let Some(err) = err {
-            let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
-            let diag = match err {
-                // why is this reported here?
-                hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
-                    always!(krate == loc.def.krate);
-                    DefDiagnostic::unresolved_proc_macro(module_id, loc.kind.clone(), loc.def.krate)
-                }
-                _ => DefDiagnostic::macro_error(module_id, loc.kind, err.to_string()),
-            };
-
-            self.def_map.diagnostics.push(diag);
-        }
-        if !errors.is_empty() {
-            let loc: MacroCallLoc = self.db.lookup_intern_macro_call(macro_call_id);
-            let diag = DefDiagnostic::macro_expansion_parse_error(module_id, loc.kind, errors);
-            self.def_map.diagnostics.push(diag);
-        }
-
         // Then, fetch and process the item tree. This will reuse the expansion result from above.
         let item_tree = self.db.file_item_tree(file_id);
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
index 8c7fdaa..523a4c1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/diagnostics.rs
@@ -6,7 +6,7 @@
 use cfg::{CfgExpr, CfgOptions};
 use hir_expand::{attrs::AttrId, ErasedAstId, MacroCallKind};
 use la_arena::Idx;
-use syntax::{ast, SyntaxError};
+use syntax::ast;
 
 use crate::{
     item_tree::{self, ItemTreeId},
@@ -23,8 +23,6 @@
     UnconfiguredCode { ast: ErasedAstId, cfg: CfgExpr, opts: CfgOptions },
     UnresolvedProcMacro { ast: MacroCallKind, krate: CrateId },
     UnresolvedMacroCall { ast: MacroCallKind, path: ModPath },
-    MacroError { ast: MacroCallKind, message: String },
-    MacroExpansionParseError { ast: MacroCallKind, errors: Box<[SyntaxError]> },
     UnimplementedBuiltinMacro { ast: AstId<ast::Macro> },
     InvalidDeriveTarget { ast: AstId<ast::Item>, id: usize },
     MalformedDerive { ast: AstId<ast::Adt>, id: usize },
@@ -98,7 +96,7 @@
     // FIXME: This is used for a lot of things, unresolved proc macros, disabled proc macros, etc
     // yet the diagnostic handler in ide-diagnostics has to figure out what happened because this
     // struct loses all that information!
-    pub(crate) fn unresolved_proc_macro(
+    pub fn unresolved_proc_macro(
         container: LocalModuleId,
         ast: MacroCallKind,
         krate: CrateId,
@@ -106,25 +104,6 @@
         Self { in_module: container, kind: DefDiagnosticKind::UnresolvedProcMacro { ast, krate } }
     }
 
-    pub(crate) fn macro_error(
-        container: LocalModuleId,
-        ast: MacroCallKind,
-        message: String,
-    ) -> Self {
-        Self { in_module: container, kind: DefDiagnosticKind::MacroError { ast, message } }
-    }
-
-    pub(crate) fn macro_expansion_parse_error(
-        container: LocalModuleId,
-        ast: MacroCallKind,
-        errors: Box<[SyntaxError]>,
-    ) -> Self {
-        Self {
-            in_module: container,
-            kind: DefDiagnosticKind::MacroExpansionParseError { ast, errors },
-        }
-    }
-
     // FIXME: Whats the difference between this and unresolved_proc_macro
     pub(crate) fn unresolved_macro_call(
         container: LocalModuleId,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
index b3c41a0..6af5261 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs
@@ -208,6 +208,13 @@
                         .and_then(|args| lower_generic_args(lower_ctx, args))
                         .map(Interned::new);
                     let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
+                    let type_ref = type_ref.inspect(|tr| {
+                        tr.walk(&mut |tr| {
+                            if let TypeRef::ImplTrait(bounds) = tr {
+                                lower_ctx.update_impl_traits_bounds(bounds.clone());
+                            }
+                        });
+                    });
                     let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
                         l.bounds()
                             .map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index fadab85..1602b17 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -1,5 +1,5 @@
 //! Name resolution façade.
-use std::{fmt, hash::BuildHasherDefault, mem};
+use std::{fmt, hash::BuildHasherDefault, iter, mem};
 
 use base_db::CrateId;
 use hir_expand::{
@@ -591,13 +591,13 @@
 
     pub fn where_predicates_in_scope(
         &self,
-    ) -> impl Iterator<Item = &crate::generics::WherePredicate> {
+    ) -> impl Iterator<Item = (&crate::generics::WherePredicate, &GenericDefId)> {
         self.scopes()
             .filter_map(|scope| match scope {
-                Scope::GenericParams { params, .. } => Some(params),
+                Scope::GenericParams { params, def } => Some((params, def)),
                 _ => None,
             })
-            .flat_map(|params| params.where_predicates.iter())
+            .flat_map(|(params, def)| params.where_predicates.iter().zip(iter::repeat(def)))
     }
 
     pub fn generic_def(&self) -> Option<GenericDefId> {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index f8bf88d..85ec02a 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -5,7 +5,7 @@
 use cfg::CfgExpr;
 use either::Either;
 use intern::Interned;
-use mbe::{syntax_node_to_token_tree, DelimiterKind, Punct};
+use mbe::{syntax_node_to_token_tree, DelimiterKind, DocCommentDesugarMode, Punct};
 use smallvec::{smallvec, SmallVec};
 use span::{Span, SyntaxContextId};
 use syntax::unescape;
@@ -239,7 +239,12 @@
                 span,
             })))
         } else if let Some(tt) = ast.token_tree() {
-            let tree = syntax_node_to_token_tree(tt.syntax(), span_map, span);
+            let tree = syntax_node_to_token_tree(
+                tt.syntax(),
+                span_map,
+                span,
+                DocCommentDesugarMode::ProcMacro,
+            );
             Some(Interned::new(AttrInput::TokenTree(Box::new(tree))))
         } else {
             None
@@ -247,8 +252,18 @@
         Some(Attr { id, path, input, ctxt: span.ctx })
     }
 
-    fn from_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree], id: AttrId) -> Option<Attr> {
-        let ctxt = tt.first()?.first_span().ctx;
+    fn from_tt(db: &dyn ExpandDatabase, mut tt: &[tt::TokenTree], id: AttrId) -> Option<Attr> {
+        if matches!(tt,
+            [tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { text, .. })), ..]
+            if text == "unsafe"
+        ) {
+            match tt.get(1) {
+                Some(tt::TokenTree::Subtree(subtree)) => tt = &subtree.token_trees,
+                _ => return None,
+            }
+        }
+        let first = &tt.first()?;
+        let ctxt = first.first_span().ctx;
         let path_end = tt
             .iter()
             .position(|tt| {
@@ -430,7 +445,7 @@
 
 // Input subtree is: `(cfg, $(attr),+)`
 // Split it up into a `cfg` subtree and the `attr` subtrees.
-pub fn parse_cfg_attr_input(
+fn parse_cfg_attr_input(
     subtree: &Subtree,
 ) -> Option<(&[tt::TokenTree], impl Iterator<Item = &[tt::TokenTree]>)> {
     let mut parts = subtree
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
index 94681b4..c7cdc5e 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
@@ -1,6 +1,7 @@
 //! Builtin derives.
 
 use itertools::izip;
+use mbe::DocCommentDesugarMode;
 use rustc_hash::FxHashSet;
 use span::{MacroCallId, Span};
 use stdx::never;
@@ -262,7 +263,12 @@
                 match this {
                     Some(it) => {
                         param_type_set.insert(it.as_name());
-                        mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site)
+                        mbe::syntax_node_to_token_tree(
+                            it.syntax(),
+                            tm,
+                            call_site,
+                            DocCommentDesugarMode::ProcMacro,
+                        )
                     }
                     None => {
                         tt::Subtree::empty(::tt::DelimSpan { open: call_site, close: call_site })
@@ -270,15 +276,27 @@
                 }
             };
             let bounds = match &param {
-                ast::TypeOrConstParam::Type(it) => it
-                    .type_bound_list()
-                    .map(|it| mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site)),
+                ast::TypeOrConstParam::Type(it) => it.type_bound_list().map(|it| {
+                    mbe::syntax_node_to_token_tree(
+                        it.syntax(),
+                        tm,
+                        call_site,
+                        DocCommentDesugarMode::ProcMacro,
+                    )
+                }),
                 ast::TypeOrConstParam::Const(_) => None,
             };
             let ty = if let ast::TypeOrConstParam::Const(param) = param {
                 let ty = param
                     .ty()
-                    .map(|ty| mbe::syntax_node_to_token_tree(ty.syntax(), tm, call_site))
+                    .map(|ty| {
+                        mbe::syntax_node_to_token_tree(
+                            ty.syntax(),
+                            tm,
+                            call_site,
+                            DocCommentDesugarMode::ProcMacro,
+                        )
+                    })
                     .unwrap_or_else(|| {
                         tt::Subtree::empty(::tt::DelimSpan { open: call_site, close: call_site })
                     });
@@ -292,7 +310,14 @@
 
     let where_clause = if let Some(w) = where_clause {
         w.predicates()
-            .map(|it| mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site))
+            .map(|it| {
+                mbe::syntax_node_to_token_tree(
+                    it.syntax(),
+                    tm,
+                    call_site,
+                    DocCommentDesugarMode::ProcMacro,
+                )
+            })
             .collect()
     } else {
         vec![]
@@ -322,7 +347,14 @@
             let name = p.path()?.qualifier()?.as_single_name_ref()?.as_name();
             param_type_set.contains(&name).then_some(p)
         })
-        .map(|it| mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site))
+        .map(|it| {
+            mbe::syntax_node_to_token_tree(
+                it.syntax(),
+                tm,
+                call_site,
+                DocCommentDesugarMode::ProcMacro,
+            )
+        })
         .collect();
     let name_token = name_to_token(tm, name)?;
     Ok(BasicAdtInfo { name: name_token, shape, param_types, where_clause, associated_types })
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
index 4d6fe6d..ba96ab6 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
@@ -441,21 +441,21 @@
     let span = lit.span;
     let lit = ast::make::tokens::literal(&lit.to_string());
     let token = ast::String::cast(lit)?;
-    token.value().map(|it| (it.into_owned(), span))
+    token.value().ok().map(|it| (it.into_owned(), span))
 }
 
 fn unquote_char(lit: &tt::Literal) -> Option<(char, Span)> {
     let span = lit.span;
     let lit = ast::make::tokens::literal(&lit.to_string());
     let token = ast::Char::cast(lit)?;
-    token.value().zip(Some(span))
+    token.value().ok().zip(Some(span))
 }
 
 fn unquote_byte_string(lit: &tt::Literal) -> Option<(Vec<u8>, Span)> {
     let span = lit.span;
     let lit = ast::make::tokens::literal(&lit.to_string());
     let token = ast::ByteString::cast(lit)?;
-    token.value().map(|it| (it.into_owned(), span))
+    token.value().ok().map(|it| (it.into_owned(), span))
 }
 
 fn compile_error_expand(
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index d7233a8..2e5fa61 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -3,7 +3,7 @@
 use base_db::{salsa, CrateId, FileId, SourceDatabase};
 use either::Either;
 use limit::Limit;
-use mbe::{syntax_node_to_token_tree, MatchedArmIndex};
+use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode, MatchedArmIndex};
 use rustc_hash::FxHashSet;
 use span::{AstIdMap, Span, SyntaxContextData, SyntaxContextId};
 use syntax::{ast, AstNode, Parse, SyntaxElement, SyntaxError, SyntaxNode, SyntaxToken, T};
@@ -132,7 +132,7 @@
     fn parse_macro_expansion_error(
         &self,
         macro_call: MacroCallId,
-    ) -> ExpandResult<Box<[SyntaxError]>>;
+    ) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>>;
 }
 
 /// This expands the given macro call, but with different arguments. This is
@@ -156,11 +156,25 @@
     // Build the subtree and token mapping for the speculative args
     let (mut tt, undo_info) = match loc.kind {
         MacroCallKind::FnLike { .. } => (
-            mbe::syntax_node_to_token_tree(speculative_args, span_map, span),
+            mbe::syntax_node_to_token_tree(
+                speculative_args,
+                span_map,
+                span,
+                if loc.def.is_proc_macro() {
+                    DocCommentDesugarMode::ProcMacro
+                } else {
+                    DocCommentDesugarMode::Mbe
+                },
+            ),
             SyntaxFixupUndoInfo::NONE,
         ),
         MacroCallKind::Attr { .. } if loc.def.is_attribute_derive() => (
-            mbe::syntax_node_to_token_tree(speculative_args, span_map, span),
+            mbe::syntax_node_to_token_tree(
+                speculative_args,
+                span_map,
+                span,
+                DocCommentDesugarMode::ProcMacro,
+            ),
             SyntaxFixupUndoInfo::NONE,
         ),
         MacroCallKind::Derive { derive_attr_index: index, .. }
@@ -176,7 +190,12 @@
 
             let censor_cfg =
                 cfg_process::process_cfg_attrs(db, speculative_args, &loc).unwrap_or_default();
-            let mut fixups = fixup::fixup_syntax(span_map, speculative_args, span);
+            let mut fixups = fixup::fixup_syntax(
+                span_map,
+                speculative_args,
+                span,
+                DocCommentDesugarMode::ProcMacro,
+            );
             fixups.append.retain(|it, _| match it {
                 syntax::NodeOrToken::Token(_) => true,
                 it => !censor.contains(it) && !censor_cfg.contains(it),
@@ -191,6 +210,7 @@
                     fixups.append,
                     fixups.remove,
                     span,
+                    DocCommentDesugarMode::ProcMacro,
                 ),
                 fixups.undo_info,
             )
@@ -212,7 +232,12 @@
             }?;
             match attr.token_tree() {
                 Some(token_tree) => {
-                    let mut tree = syntax_node_to_token_tree(token_tree.syntax(), span_map, span);
+                    let mut tree = syntax_node_to_token_tree(
+                        token_tree.syntax(),
+                        span_map,
+                        span,
+                        DocCommentDesugarMode::ProcMacro,
+                    );
                     tree.delimiter = tt::Delimiter::invisible_spanned(span);
 
                     Some(tree)
@@ -332,9 +357,14 @@
 fn parse_macro_expansion_error(
     db: &dyn ExpandDatabase,
     macro_call_id: MacroCallId,
-) -> ExpandResult<Box<[SyntaxError]>> {
-    db.parse_macro_expansion(MacroFileId { macro_call_id })
-        .map(|it| it.0.errors().into_boxed_slice())
+) -> Option<Arc<ExpandResult<Arc<[SyntaxError]>>>> {
+    let e: ExpandResult<Arc<[SyntaxError]>> =
+        db.parse_macro_expansion(MacroFileId { macro_call_id }).map(|it| Arc::from(it.0.errors()));
+    if e.value.is_empty() && e.err.is_none() {
+        None
+    } else {
+        Some(Arc::new(e))
+    }
 }
 
 pub(crate) fn parse_with_map(
@@ -432,7 +462,16 @@
                 return dummy_tt(kind);
             }
 
-            let mut tt = mbe::syntax_node_to_token_tree(tt.syntax(), map.as_ref(), span);
+            let mut tt = mbe::syntax_node_to_token_tree(
+                tt.syntax(),
+                map.as_ref(),
+                span,
+                if loc.def.is_proc_macro() {
+                    DocCommentDesugarMode::ProcMacro
+                } else {
+                    DocCommentDesugarMode::Mbe
+                },
+            );
             if loc.def.is_proc_macro() {
                 // proc macros expect their inputs without parentheses, MBEs expect it with them included
                 tt.delimiter.kind = tt::DelimiterKind::Invisible;
@@ -469,7 +508,8 @@
     let (mut tt, undo_info) = {
         let syntax = item_node.syntax();
         let censor_cfg = cfg_process::process_cfg_attrs(db, syntax, &loc).unwrap_or_default();
-        let mut fixups = fixup::fixup_syntax(map.as_ref(), syntax, span);
+        let mut fixups =
+            fixup::fixup_syntax(map.as_ref(), syntax, span, DocCommentDesugarMode::ProcMacro);
         fixups.append.retain(|it, _| match it {
             syntax::NodeOrToken::Token(_) => true,
             it => !censor.contains(it) && !censor_cfg.contains(it),
@@ -484,6 +524,7 @@
                 fixups.append,
                 fixups.remove,
                 span,
+                DocCommentDesugarMode::ProcMacro,
             ),
             fixups.undo_info,
         )
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
index 66465ce..7c3bf99 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/declarative.rs
@@ -2,6 +2,7 @@
 use std::sync::OnceLock;
 
 use base_db::{CrateId, VersionReq};
+use mbe::DocCommentDesugarMode;
 use span::{Edition, MacroCallId, Span, SyntaxContextId};
 use stdx::TupleExt;
 use syntax::{ast, AstNode};
@@ -158,6 +159,7 @@
                             map.span_for_range(
                                 macro_rules.macro_rules_token().unwrap().text_range(),
                             ),
+                            DocCommentDesugarMode::Mbe,
                         );
 
                         mbe::DeclarativeMacro::parse_macro_rules(&tt, edition, new_meta_vars)
@@ -175,6 +177,7 @@
                             arg.syntax(),
                             map.as_ref(),
                             map.span_for_range(macro_def.macro_token().unwrap().text_range()),
+                            DocCommentDesugarMode::Mbe,
                         );
 
                         mbe::DeclarativeMacro::parse_macro2(&tt, edition, new_meta_vars)
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
index 8b147c8..64e04bc 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs
@@ -19,6 +19,7 @@
 //!
 //! See the full discussion : <https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/Eager.20expansion.20of.20built-in.20macros>
 use base_db::CrateId;
+use mbe::DocCommentDesugarMode;
 use span::SyntaxContextId;
 use syntax::{ted, Parse, SyntaxElement, SyntaxNode, TextSize, WalkEvent};
 use triomphe::Arc;
@@ -80,7 +81,12 @@
         return ExpandResult { value: None, err };
     };
 
-    let mut subtree = mbe::syntax_node_to_token_tree(&expanded_eager_input, arg_map, span);
+    let mut subtree = mbe::syntax_node_to_token_tree(
+        &expanded_eager_input,
+        arg_map,
+        span,
+        DocCommentDesugarMode::Mbe,
+    );
 
     subtree.delimiter.kind = crate::tt::DelimiterKind::Invisible;
 
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
index 711acfe..9ec2a83 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
@@ -1,6 +1,7 @@
 //! To make attribute macros work reliably when typing, we need to take care to
 //! fix up syntax errors in the code we're passing to them.
 
+use mbe::DocCommentDesugarMode;
 use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::SmallVec;
 use span::{ErasedFileAstId, Span, SpanAnchor, FIXUP_ERASED_FILE_AST_ID_MARKER};
@@ -49,6 +50,7 @@
     span_map: SpanMapRef<'_>,
     node: &SyntaxNode,
     call_site: Span,
+    mode: DocCommentDesugarMode,
 ) -> SyntaxFixups {
     let mut append = FxHashMap::<SyntaxElement, _>::default();
     let mut remove = FxHashSet::<SyntaxElement>::default();
@@ -70,7 +72,7 @@
         if can_handle_error(&node) && has_error_to_handle(&node) {
             remove.insert(node.clone().into());
             // the node contains an error node, we have to completely replace it by something valid
-            let original_tree = mbe::syntax_node_to_token_tree(&node, span_map, call_site);
+            let original_tree = mbe::syntax_node_to_token_tree(&node, span_map, call_site, mode);
             let idx = original.len() as u32;
             original.push(original_tree);
             let span = span_map.span_for_range(node_range);
@@ -360,6 +362,7 @@
 mod tests {
     use base_db::FileId;
     use expect_test::{expect, Expect};
+    use mbe::DocCommentDesugarMode;
     use syntax::TextRange;
     use triomphe::Arc;
 
@@ -402,6 +405,7 @@
             span_map.as_ref(),
             &parsed.syntax_node(),
             span_map.span_for_range(TextRange::empty(0.into())),
+            DocCommentDesugarMode::Mbe,
         );
         let mut tt = mbe::syntax_node_to_token_tree_modified(
             &parsed.syntax_node(),
@@ -409,6 +413,7 @@
             fixups.append,
             fixups.remove,
             span_map.span_for_range(TextRange::empty(0.into())),
+            DocCommentDesugarMode::Mbe,
         );
 
         let actual = format!("{tt}\n");
@@ -436,6 +441,7 @@
             &parsed.syntax_node(),
             span_map.as_ref(),
             span_map.span_for_range(TextRange::empty(0.into())),
+            DocCommentDesugarMode::Mbe,
         );
         assert!(
             check_subtree_eq(&tt, &original_as_tt),
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index 338bd25..4ab989b 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -132,13 +132,13 @@
     MacroDefinition,
     Mbe(mbe::ExpandError),
     RecursionOverflow,
-    Other(Box<Box<str>>),
-    ProcMacroPanic(Box<Box<str>>),
+    Other(Arc<Box<str>>),
+    ProcMacroPanic(Arc<Box<str>>),
 }
 
 impl ExpandError {
     pub fn other(msg: impl Into<Box<str>>) -> Self {
-        ExpandError::Other(Box::new(msg.into()))
+        ExpandError::Other(Arc::new(msg.into()))
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
index abed16f..def2578 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs
@@ -8,6 +8,7 @@
 use span::Span;
 use stdx::never;
 use syntax::SmolStr;
+use triomphe::Arc;
 
 use crate::{db::ExpandDatabase, tt, ExpandError, ExpandResult};
 
@@ -157,7 +158,7 @@
                         ProcMacroExpansionError::System(text)
                         | ProcMacroExpansionError::Panic(text) => ExpandResult::new(
                             tt::Subtree::empty(tt::DelimSpan { open: call_site, close: call_site }),
-                            ExpandError::ProcMacroPanic(Box::new(text.into_boxed_str())),
+                            ExpandError::ProcMacroPanic(Arc::new(text.into_boxed_str())),
                         ),
                     },
                 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
index 4661224..84ac874 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
@@ -806,7 +806,7 @@
     krate: CrateId,
     impl_id: ImplId,
 ) -> Arc<ImplDatum> {
-    let _p = tracing::span!(tracing::Level::INFO, "impl_datum").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "impl_datum_query").entered();
     debug!("impl_datum {:?}", impl_id);
     let impl_: hir_def::ImplId = from_chalk(db, impl_id);
     impl_def_datum(db, krate, impl_id, impl_)
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
index 0bf01b0..d99ef667 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs
@@ -27,6 +27,7 @@
     fn is_scalar(&self) -> bool;
     fn is_floating_point(&self) -> bool;
     fn is_never(&self) -> bool;
+    fn is_str(&self) -> bool;
     fn is_unknown(&self) -> bool;
     fn contains_unknown(&self) -> bool;
     fn is_ty_var(&self) -> bool;
@@ -87,6 +88,10 @@
         matches!(self.kind(Interner), TyKind::Never)
     }
 
+    fn is_str(&self) -> bool {
+        matches!(self.kind(Interner), TyKind::Str)
+    }
+
     fn is_unknown(&self) -> bool {
         matches!(self.kind(Interner), TyKind::Error)
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index a357e85..c010f5d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -797,8 +797,20 @@
                 c.hir_fmt(f)?;
                 write!(f, "]")?;
             }
-            TyKind::Raw(m, t) | TyKind::Ref(m, _, t) => {
-                if matches!(self.kind(Interner), TyKind::Raw(..)) {
+            kind @ (TyKind::Raw(m, t) | TyKind::Ref(m, _, t)) => {
+                if let TyKind::Ref(_, l, _) = kind {
+                    f.write_char('&')?;
+                    if cfg!(test) {
+                        // rendering these unconditionally is probably too much (at least for inlay
+                        // hints) so we gate it to testing only for the time being
+                        l.hir_fmt(f)?;
+                        f.write_char(' ')?;
+                    }
+                    match m {
+                        Mutability::Not => (),
+                        Mutability::Mut => f.write_str("mut ")?,
+                    }
+                } else {
                     write!(
                         f,
                         "*{}",
@@ -807,15 +819,6 @@
                             Mutability::Mut => "mut ",
                         }
                     )?;
-                } else {
-                    write!(
-                        f,
-                        "&{}",
-                        match m {
-                            Mutability::Not => "",
-                            Mutability::Mut => "mut ",
-                        }
-                    )?;
                 }
 
                 // FIXME: all this just to decide whether to use parentheses...
@@ -1330,7 +1333,18 @@
     }
 
     let parameters_to_write = generic_args_sans_defaults(f, generic_def, parameters);
-    if !parameters_to_write.is_empty() {
+
+    // FIXME: Remote this
+    // most of our lifetimes will be errors as we lack elision and inference
+    // so don't render them for now
+    let only_err_lifetimes = !cfg!(test)
+        && parameters_to_write.iter().all(|arg| {
+            matches!(
+                arg.data(Interner),
+                chalk_ir::GenericArgData::Lifetime(it) if *it.data(Interner) == LifetimeData::Error
+            )
+        });
+    if !parameters_to_write.is_empty() && !only_err_lifetimes {
         write!(f, "<")?;
         hir_fmt_generic_arguments(f, parameters_to_write)?;
         write!(f, ">")?;
@@ -1403,6 +1417,18 @@
         None => (parameters, &[][..]),
     };
     for generic_arg in lifetimes.iter().chain(ty_or_const) {
+        // FIXME: Remove this
+        // most of our lifetimes will be errors as we lack elision and inference
+        // so don't render them for now
+        if !cfg!(test)
+            && matches!(
+                generic_arg.lifetime(Interner),
+                Some(l) if ***l.interned() == LifetimeData::Error
+            )
+        {
+            continue;
+        }
+
         if !first {
             write!(f, ", ")?;
         }
@@ -1728,9 +1754,9 @@
             LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
             LifetimeData::InferenceVar(_) => write!(f, "_"),
             LifetimeData::Static => write!(f, "'static"),
-            LifetimeData::Error => write!(f, "'{{error}}"),
-            LifetimeData::Erased => Ok(()),
-            LifetimeData::Phantom(_, _) => Ok(()),
+            LifetimeData::Error => write!(f, "'?"),
+            LifetimeData::Erased => write!(f, "'<erased>"),
+            LifetimeData::Phantom(void, _) => match *void {},
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
index 281386e..6f2f70d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -198,6 +198,7 @@
     NoSuchField {
         field: ExprOrPatId,
         private: bool,
+        variant: VariantId,
     },
     PrivateField {
         expr: ExprId,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index d011a62..38076fc 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -563,6 +563,7 @@
                                                 InferenceDiagnostic::NoSuchField {
                                                     field: field.expr.into(),
                                                     private: true,
+                                                    variant: def,
                                                 },
                                             );
                                         }
@@ -572,6 +573,7 @@
                                         self.push_diagnostic(InferenceDiagnostic::NoSuchField {
                                             field: field.expr.into(),
                                             private: false,
+                                            variant: def,
                                         });
                                         None
                                     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
index 1b35493..dac5a5e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
@@ -177,6 +177,7 @@
                                     self.push_diagnostic(InferenceDiagnostic::NoSuchField {
                                         field: inner.into(),
                                         private: true,
+                                        variant: def,
                                     });
                                 }
                                 let f = field_types[local_id].clone();
@@ -190,6 +191,7 @@
                                 self.push_diagnostic(InferenceDiagnostic::NoSuchField {
                                     field: inner.into(),
                                     private: false,
+                                    variant: def,
                                 });
                                 self.err_ty()
                             }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index dd949e2..d9fd029 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -6,8 +6,8 @@
 use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
 use hir_def::{
     layout::{
-        Abi, FieldsShape, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions, Scalar, Size,
-        StructKind, TargetDataLayout, WrappingRange,
+        Abi, FieldsShape, Float, Integer, LayoutCalculator, LayoutS, Primitive, ReprOptions,
+        Scalar, Size, StructKind, TargetDataLayout, WrappingRange,
     },
     LocalFieldId, StructId,
 };
@@ -264,10 +264,10 @@
             ),
             chalk_ir::Scalar::Float(f) => scalar(
                 dl,
-                match f {
-                    FloatTy::F32 => Primitive::F32,
-                    FloatTy::F64 => Primitive::F64,
-                },
+                Primitive::Float(match f {
+                    FloatTy::F32 => Float::F32,
+                    FloatTy::F64 => Float::F64,
+                }),
             ),
         },
         TyKind::Tuple(len, tys) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 4d0516e..04ace38 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -345,51 +345,47 @@
                     }
                     ImplTraitLoweringState::Param(counter) => {
                         let idx = counter.get();
-                        // FIXME we're probably doing something wrong here
+                        // Count the number of `impl Trait` things that appear within our bounds.
+                        // Since t hose have been emitted as implicit type args already.
                         counter.set(idx + count_impl_traits(type_ref) as u16);
-                        if let Some(generics) = self.generics() {
-                            let param = generics
-                                .iter()
-                                .filter(|(_, data)| {
-                                    matches!(
-                                        data,
-                                        GenericParamDataRef::TypeParamData(data)
-                                        if data.provenance == TypeParamProvenance::ArgumentImplTrait
-                                    )
-                                })
-                                .nth(idx as usize)
-                                .map_or(TyKind::Error, |(id, _)| {
-                                    if let GenericParamId::TypeParamId(id) = id {
-                                        TyKind::Placeholder(to_placeholder_idx(self.db, id.into()))
-                                    } else {
-                                        // we just filtered them out
-                                        unreachable!("Unexpected lifetime or const argument");
-                                    }
-                                });
-                            param.intern(Interner)
-                        } else {
-                            TyKind::Error.intern(Interner)
-                        }
+                        let kind = self
+                            .generics()
+                            .expect("param impl trait lowering must be in a generic def")
+                            .iter()
+                            .filter_map(|(id, data)| match (id, data) {
+                                (
+                                    GenericParamId::TypeParamId(id),
+                                    GenericParamDataRef::TypeParamData(data),
+                                ) if data.provenance == TypeParamProvenance::ArgumentImplTrait => {
+                                    Some(id)
+                                }
+                                _ => None,
+                            })
+                            .nth(idx as usize)
+                            .map_or(TyKind::Error, |id| {
+                                TyKind::Placeholder(to_placeholder_idx(self.db, id.into()))
+                            });
+                        kind.intern(Interner)
                     }
                     ImplTraitLoweringState::Variable(counter) => {
                         let idx = counter.get();
-                        // FIXME we're probably doing something wrong here
+                        // Count the number of `impl Trait` things that appear within our bounds.
+                        // Since t hose have been emitted as implicit type args already.
                         counter.set(idx + count_impl_traits(type_ref) as u16);
                         let (
                             _parent_params,
                             self_params,
-                            list_params,
+                            type_params,
                             const_params,
                             _impl_trait_params,
                             _lifetime_params,
-                        ) = if let Some(generics) = self.generics() {
-                            generics.provenance_split()
-                        } else {
-                            (0, 0, 0, 0, 0, 0)
-                        };
+                        ) = self
+                            .generics()
+                            .expect("variable impl trait lowering must be in a generic def")
+                            .provenance_split();
                         TyKind::BoundVar(BoundVar::new(
                             self.in_binders,
-                            idx as usize + self_params + list_params + const_params,
+                            idx as usize + self_params + type_params + const_params,
                         ))
                         .intern(Interner)
                     }
@@ -1010,6 +1006,7 @@
     pub(crate) fn lower_where_predicate<'b>(
         &'b self,
         where_predicate: &'b WherePredicate,
+        &def: &GenericDefId,
         ignore_bindings: bool,
     ) -> impl Iterator<Item = QuantifiedWhereClause> + 'b {
         match where_predicate {
@@ -1018,7 +1015,6 @@
                 let self_ty = match target {
                     WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref),
                     &WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
-                        let def = self.resolver.generic_def().expect("generics in scope");
                         let param_id = hir_def::TypeOrConstParamId { parent: def, local_id };
                         match self.type_param_mode {
                             ParamLoweringMode::Placeholder => {
@@ -1056,23 +1052,7 @@
         let clause = match bound.as_ref() {
             TypeBound::Path(path, TraitBoundModifier::None) => {
                 trait_ref = self.lower_trait_ref_from_path(path, Some(self_ty));
-                trait_ref
-                    .clone()
-                    .filter(|tr| {
-                        // ignore `T: Drop` or `T: Destruct` bounds.
-                        // - `T: ~const Drop` has a special meaning in Rust 1.61 that we don't implement.
-                        //   (So ideally, we'd only ignore `~const Drop` here)
-                        // - `Destruct` impls are built-in in 1.62 (current nightly as of 08-04-2022), so until
-                        //   the builtin impls are supported by Chalk, we ignore them here.
-                        if let Some(lang) = self.db.lang_attr(tr.hir_trait_id().into()) {
-                            if matches!(lang, LangItem::Drop | LangItem::Destruct) {
-                                return false;
-                            }
-                        }
-                        true
-                    })
-                    .map(WhereClause::Implemented)
-                    .map(crate::wrap_empty_binders)
+                trait_ref.clone().map(WhereClause::Implemented).map(crate::wrap_empty_binders)
             }
             TypeBound::Path(path, TraitBoundModifier::Maybe) => {
                 let sized_trait = self
@@ -1166,84 +1146,77 @@
                     binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
                 );
                 if let Some(type_ref) = &binding.type_ref {
-                    if let (
-                        TypeRef::ImplTrait(bounds),
-                        ImplTraitLoweringState::Param(_)
-                        | ImplTraitLoweringState::Variable(_)
-                        | ImplTraitLoweringState::Disallowed,
-                    ) = (type_ref, &self.impl_trait_mode)
-                    {
-                        for bound in bounds {
-                            predicates.extend(
-                                self.lower_type_bound(
-                                    bound,
-                                    TyKind::Alias(AliasTy::Projection(projection_ty.clone()))
-                                        .intern(Interner),
-                                    false,
-                                ),
-                            );
+                    match (type_ref, &self.impl_trait_mode) {
+                        (TypeRef::ImplTrait(_), ImplTraitLoweringState::Disallowed) => (),
+                        (
+                            _,
+                            ImplTraitLoweringState::Disallowed | ImplTraitLoweringState::Opaque(_),
+                        ) => {
+                            let ty = self.lower_ty(type_ref);
+                            let alias_eq =
+                                AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
+                            predicates
+                                .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
                         }
-                    } else {
-                        let ty = 'ty: {
-                            if matches!(
-                                self.impl_trait_mode,
-                                ImplTraitLoweringState::Param(_)
-                                    | ImplTraitLoweringState::Variable(_)
-                            ) {
-                                // Find the generic index for the target of our `bound`
-                                let target_param_idx = self
-                                    .resolver
-                                    .where_predicates_in_scope()
-                                    .find_map(|p| match p {
-                                        WherePredicate::TypeBound {
-                                            target: WherePredicateTypeTarget::TypeOrConstParam(idx),
-                                            bound: b,
-                                        } if b == bound => Some(idx),
-                                        _ => None,
-                                    });
-                                if let Some(target_param_idx) = target_param_idx {
-                                    let mut counter = 0;
-                                    let generics = self.generics().expect("generics in scope");
-                                    for (idx, data) in generics.params.type_or_consts.iter() {
-                                        // Count the number of `impl Trait` things that appear before
-                                        // the target of our `bound`.
-                                        // Our counter within `impl_trait_mode` should be that number
-                                        // to properly lower each types within `type_ref`
-                                        if data.type_param().is_some_and(|p| {
-                                            p.provenance == TypeParamProvenance::ArgumentImplTrait
-                                        }) {
-                                            counter += 1;
-                                        }
-                                        if idx == *target_param_idx {
-                                            break;
-                                        }
+                        (
+                            _,
+                            ImplTraitLoweringState::Param(_) | ImplTraitLoweringState::Variable(_),
+                        ) => {
+                            // Find the generic index for the target of our `bound`
+                            let target_param_idx = self
+                                .resolver
+                                .where_predicates_in_scope()
+                                .find_map(|(p, _)| match p {
+                                    WherePredicate::TypeBound {
+                                        target: WherePredicateTypeTarget::TypeOrConstParam(idx),
+                                        bound: b,
+                                    } if b == bound => Some(idx),
+                                    _ => None,
+                                });
+                            let ty = if let Some(target_param_idx) = target_param_idx {
+                                let mut counter = 0;
+                                let generics = self.generics().expect("generics in scope");
+                                for (idx, data) in generics.params.type_or_consts.iter() {
+                                    // Count the number of `impl Trait` things that appear before
+                                    // the target of our `bound`.
+                                    // Our counter within `impl_trait_mode` should be that number
+                                    // to properly lower each types within `type_ref`
+                                    if data.type_param().is_some_and(|p| {
+                                        p.provenance == TypeParamProvenance::ArgumentImplTrait
+                                    }) {
+                                        counter += 1;
                                     }
-                                    let mut ext = TyLoweringContext::new_maybe_unowned(
-                                        self.db,
-                                        self.resolver,
-                                        self.owner,
-                                    )
-                                    .with_type_param_mode(self.type_param_mode);
-                                    match &self.impl_trait_mode {
-                                        ImplTraitLoweringState::Param(_) => {
-                                            ext.impl_trait_mode =
-                                                ImplTraitLoweringState::Param(Cell::new(counter));
-                                        }
-                                        ImplTraitLoweringState::Variable(_) => {
-                                            ext.impl_trait_mode = ImplTraitLoweringState::Variable(
-                                                Cell::new(counter),
-                                            );
-                                        }
-                                        _ => unreachable!(),
+                                    if idx == *target_param_idx {
+                                        break;
                                     }
-                                    break 'ty ext.lower_ty(type_ref);
                                 }
-                            }
-                            self.lower_ty(type_ref)
-                        };
-                        let alias_eq =
-                            AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
-                        predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
+                                let mut ext = TyLoweringContext::new_maybe_unowned(
+                                    self.db,
+                                    self.resolver,
+                                    self.owner,
+                                )
+                                .with_type_param_mode(self.type_param_mode);
+                                match &self.impl_trait_mode {
+                                    ImplTraitLoweringState::Param(_) => {
+                                        ext.impl_trait_mode =
+                                            ImplTraitLoweringState::Param(Cell::new(counter));
+                                    }
+                                    ImplTraitLoweringState::Variable(_) => {
+                                        ext.impl_trait_mode =
+                                            ImplTraitLoweringState::Variable(Cell::new(counter));
+                                    }
+                                    _ => unreachable!(),
+                                }
+                                ext.lower_ty(type_ref)
+                            } else {
+                                self.lower_ty(type_ref)
+                            };
+
+                            let alias_eq =
+                                AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
+                            predicates
+                                .push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
+                        }
                     }
                 }
                 for bound in binding.bounds.iter() {
@@ -1338,11 +1311,10 @@
                 bounds,
                 lifetime: match lifetime {
                     Some(it) => match it.bound_var(Interner) {
-                        Some(bound_var) => LifetimeData::BoundVar(BoundVar::new(
-                            DebruijnIndex::INNERMOST,
-                            bound_var.index,
-                        ))
-                        .intern(Interner),
+                        Some(bound_var) => bound_var
+                            .shifted_out_to(DebruijnIndex::new(2))
+                            .map(|bound_var| LifetimeData::BoundVar(bound_var).intern(Interner))
+                            .unwrap_or(it),
                         None => it,
                     },
                     None => static_lifetime(),
@@ -1410,16 +1382,6 @@
     }
 }
 
-fn count_impl_traits(type_ref: &TypeRef) -> usize {
-    let mut count = 0;
-    type_ref.walk(&mut |type_ref| {
-        if matches!(type_ref, TypeRef::ImplTrait(_)) {
-            count += 1;
-        }
-    });
-    count
-}
-
 /// Build the signature of a callable item (function, struct or enum variant).
 pub(crate) fn callable_item_sig(db: &dyn HirDatabase, def: CallableDefId) -> PolyFnSig {
     match def {
@@ -1438,6 +1400,17 @@
     named_associated_type_shorthand_candidates(db, def, res, None, |name, _, id| cb(name, id))
 }
 
+// FIXME: This does not handle macros!
+fn count_impl_traits(type_ref: &TypeRef) -> usize {
+    let mut count = 0;
+    type_ref.walk(&mut |type_ref| {
+        if matches!(type_ref, TypeRef::ImplTrait(_)) {
+            count += 1;
+        }
+    });
+    count
+}
+
 fn named_associated_type_shorthand_candidates<R>(
     db: &dyn HirDatabase,
     // If the type parameter is defined in an impl and we're in a method, there
@@ -1575,7 +1548,7 @@
     let generics = generics(db.upcast(), def);
 
     // we have to filter out all other predicates *first*, before attempting to lower them
-    let predicate = |pred: &&_| match pred {
+    let predicate = |(pred, &def): &(&_, _)| match pred {
         WherePredicate::ForLifetime { target, bound, .. }
         | WherePredicate::TypeBound { target, bound, .. } => {
             let invalid_target = match target {
@@ -1617,8 +1590,8 @@
     let mut predicates: Vec<_> = resolver
         .where_predicates_in_scope()
         .filter(predicate)
-        .flat_map(|pred| {
-            ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p))
+        .flat_map(|(pred, def)| {
+            ctx.lower_where_predicate(pred, def, true).map(|p| make_binders(db, &generics, p))
         })
         .collect();
 
@@ -1671,8 +1644,8 @@
     };
     let mut traits_in_scope = Vec::new();
     let mut clauses = Vec::new();
-    for pred in resolver.where_predicates_in_scope() {
-        for pred in ctx.lower_where_predicate(pred, false) {
+    for (pred, def) in resolver.where_predicates_in_scope() {
+        for pred in ctx.lower_where_predicate(pred, def, false) {
             if let WhereClause::Implemented(tr) = &pred.skip_binders() {
                 traits_in_scope.push((tr.self_type_parameter(Interner).clone(), tr.hir_trait_id()));
             }
@@ -1726,8 +1699,8 @@
 
     let mut predicates = resolver
         .where_predicates_in_scope()
-        .flat_map(|pred| {
-            ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p))
+        .flat_map(|(pred, def)| {
+            ctx.lower_where_predicate(pred, def, false).map(|p| make_binders(db, &generics, p))
         })
         .collect::<Vec<_>>();
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index cd72349..cb56a6f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -368,7 +368,7 @@
     krate: CrateId,
     fp: TyFingerprint,
 ) -> SmallVec<[CrateId; 2]> {
-    let _p = tracing::span!(tracing::Level::INFO, "inherent_impl_crates_query").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "incoherent_inherent_impl_crates").entered();
     let mut res = SmallVec::new();
     let crate_graph = db.crate_graph();
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index 045ffb4..2de1aa3 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -428,6 +428,17 @@
         }
         Ok(())
     }
+
+    pub fn is_panic(&self) -> Option<&str> {
+        let mut err = self;
+        while let MirEvalError::InFunction(e, _) = err {
+            err = e;
+        }
+        match err {
+            MirEvalError::Panic(msg) => Some(msg),
+            _ => None,
+        }
+    }
 }
 
 impl std::fmt::Debug for MirEvalError {
@@ -1138,7 +1149,7 @@
                 let mut ty = self.operand_ty(lhs, locals)?;
                 while let TyKind::Ref(_, _, z) = ty.kind(Interner) {
                     ty = z.clone();
-                    let size = if ty.kind(Interner) == &TyKind::Str {
+                    let size = if ty.is_str() {
                         if *op != BinOp::Eq {
                             never!("Only eq is builtin for `str`");
                         }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index fee3dd3..3438712 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -49,6 +49,7 @@
         if self.not_special_fn_cache.borrow().contains(&def) {
             return Ok(false);
         }
+
         let function_data = self.db.function_data(def);
         let is_intrinsic = match &function_data.abi {
             Some(abi) => *abi == Interned::new_str("rust-intrinsic"),
@@ -131,9 +132,7 @@
             return Ok(true);
         }
         if let Some(it) = self.detect_lang_function(def) {
-            let arg_bytes =
-                args.iter().map(|it| Ok(it.get(self)?.to_owned())).collect::<Result<Vec<_>>>()?;
-            let result = self.exec_lang_item(it, generic_args, &arg_bytes, locals, span)?;
+            let result = self.exec_lang_item(it, generic_args, args, locals, span)?;
             destination.write_from_bytes(self, &result)?;
             return Ok(true);
         }
@@ -311,16 +310,20 @@
 
     fn detect_lang_function(&self, def: FunctionId) -> Option<LangItem> {
         use LangItem::*;
-        let candidate = self.db.lang_attr(def.into())?;
+        let attrs = self.db.attrs(def.into());
+
+        if attrs.by_key("rustc_const_panic_str").exists() {
+            // `#[rustc_const_panic_str]` is treated like `lang = "begin_panic"` by rustc CTFE.
+            return Some(LangItem::BeginPanic);
+        }
+
+        let candidate = attrs.by_key("lang").string_value().and_then(LangItem::from_str)?;
         // We want to execute these functions with special logic
         // `PanicFmt` is not detected here as it's redirected later.
         if [BeginPanic, SliceLen, DropInPlace].contains(&candidate) {
             return Some(candidate);
         }
-        if self.db.attrs(def.into()).by_key("rustc_const_panic_str").exists() {
-            // `#[rustc_const_panic_str]` is treated like `lang = "begin_panic"` by rustc CTFE.
-            return Some(LangItem::BeginPanic);
-        }
+
         None
     }
 
@@ -328,18 +331,52 @@
         &mut self,
         it: LangItem,
         generic_args: &Substitution,
-        args: &[Vec<u8>],
+        args: &[IntervalAndTy],
         locals: &Locals,
         span: MirSpan,
     ) -> Result<Vec<u8>> {
         use LangItem::*;
         let mut args = args.iter();
         match it {
-            BeginPanic => Err(MirEvalError::Panic("<unknown-panic-payload>".to_owned())),
+            BeginPanic => {
+                let mut arg = args
+                    .next()
+                    .ok_or(MirEvalError::InternalError(
+                        "argument of BeginPanic is not provided".into(),
+                    ))?
+                    .clone();
+                while let TyKind::Ref(_, _, ty) = arg.ty.kind(Interner) {
+                    if ty.is_str() {
+                        let (pointee, metadata) = arg.interval.get(self)?.split_at(self.ptr_size());
+                        let len = from_bytes!(usize, metadata);
+
+                        return {
+                            Err(MirEvalError::Panic(
+                                std::str::from_utf8(
+                                    self.read_memory(Address::from_bytes(pointee)?, len)?,
+                                )
+                                .unwrap()
+                                .to_owned(),
+                            ))
+                        };
+                    }
+                    let size = self.size_of_sized(ty, locals, "begin panic arg")?;
+                    let pointee = arg.interval.get(self)?;
+                    arg = IntervalAndTy {
+                        interval: Interval::new(Address::from_bytes(pointee)?, size),
+                        ty: ty.clone(),
+                    };
+                }
+                Err(MirEvalError::Panic(format!(
+                    "unknown-panic-payload: {:?}",
+                    arg.ty.kind(Interner)
+                )))
+            }
             SliceLen => {
                 let arg = args.next().ok_or(MirEvalError::InternalError(
                     "argument of <[T]>::len() is not provided".into(),
                 ))?;
+                let arg = arg.get(self)?;
                 let ptr_size = arg.len() / 2;
                 Ok(arg[ptr_size..].into())
             }
@@ -353,6 +390,7 @@
                 let arg = args.next().ok_or(MirEvalError::InternalError(
                     "argument of drop_in_place is not provided".into(),
                 ))?;
+                let arg = arg.interval.get(self)?.to_owned();
                 self.run_drop_glue_deep(
                     ty.clone(),
                     locals,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
index 381522c..4abbda5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs
@@ -31,6 +31,7 @@
             db.trait_environment(func_id.into()),
         )
         .map_err(|e| MirEvalError::MirLowerError(func_id, e))?;
+
     let (result, output) = interpret_mir(db, body, false, None);
     result?;
     Ok((output.stdout().into_owned(), output.stderr().into_owned()))
@@ -72,6 +73,13 @@
     }
 }
 
+fn check_panic(ra_fixture: &str, expected_panic: &str) {
+    let (db, file_ids) = TestDB::with_many_files(ra_fixture);
+    let file_id = *file_ids.last().unwrap();
+    let e = eval_main(&db, file_id).unwrap_err();
+    assert_eq!(e.is_panic().unwrap_or_else(|| panic!("unexpected error: {:?}", e)), expected_panic);
+}
+
 #[test]
 fn function_with_extern_c_abi() {
     check_pass(
@@ -88,6 +96,43 @@
 }
 
 #[test]
+fn panic_fmt() {
+    // panic!
+    // -> panic_2021 (builtin macro redirection)
+    //   -> #[lang = "panic_fmt"] core::panicking::panic_fmt (hooked by CTFE for redirection)
+    //   -> core::panicking::const_panic_fmt
+    //     -> #[rustc_const_panic_str] core::panicking::panic_display (hooked by CTFE for builtin panic)
+    //       -> Err(ConstEvalError::Panic)
+    check_panic(
+        r#"
+//- minicore: fmt, panic
+fn main() {
+    panic!("hello, world!");
+}
+    "#,
+        "hello, world!",
+    );
+}
+
+#[test]
+fn panic_display() {
+    // panic!
+    // -> panic_2021 (builtin macro redirection)
+    //   -> #[rustc_const_panic_str] core::panicking::panic_display (hooked by CTFE for builtin panic)
+    //     -> Err(ConstEvalError::Panic)
+    check_panic(
+        r#"
+//- minicore: fmt, panic
+
+fn main() {
+    panic!("{}", "hello, world!");
+}
+    "#,
+        "hello, world!",
+    );
+}
+
+#[test]
 fn drop_basic() {
     check_pass(
         r#"
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
index d56b15b..526db2a 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/coercion.rs
@@ -186,7 +186,7 @@
     let x = match 1 {
         1 => t as *mut i32,
         2 => t as &i32,
-           //^^^^^^^^^ expected *mut i32, got &i32
+           //^^^^^^^^^ expected *mut i32, got &'? i32
         _ => t as *const i32,
           // ^^^^^^^^^^^^^^^ adjustments: Pointer(MutToConstPointer)
 
@@ -307,7 +307,7 @@
     let foo = Foo;
       //^^^ type: Foo<{unknown}>
     let _: &u32 = &Foo;
-                //^^^^ expected &u32, got &Foo<{unknown}>
+                //^^^^ expected &'? u32, got &'? Foo<{unknown}>
 }",
     );
 }
@@ -544,9 +544,9 @@
 
 fn test() {
     let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] };
-                         //^^^^^^^^^^^^^^^^^^^^^ expected &Foo<[usize]>, got &Foo<[i32; 3]>
+                         //^^^^^^^^^^^^^^^^^^^^^ expected &'? Foo<[usize]>, got &'? Foo<[i32; 3]>
     let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
-                         //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &Bar<[usize]>, got &Bar<[i32; 3]>
+                         //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &'? Bar<[usize]>, got &'? Bar<[i32; 3]>
 }
 "#,
     );
@@ -562,7 +562,7 @@
 fn test(f: impl Foo, g: &(impl Foo + ?Sized)) {
     let _: &dyn Foo = &f;
     let _: &dyn Foo = g;
-                    //^ expected &dyn Foo, got &impl Foo + ?Sized
+                    //^ expected &'? dyn Foo, got &'? impl Foo + ?Sized
 }
         "#,
     );
@@ -828,11 +828,11 @@
 fn main() {
     let a: V<&dyn Tr>;
     (a,) = V { t: &S };
-  //^^^^expected V<&S>, got (V<&dyn Tr>,)
+  //^^^^expected V<&'? S>, got (V<&'? dyn Tr>,)
 
     let mut a: V<&dyn Tr> = V { t: &S };
     (a,) = V { t: &S };
-  //^^^^expected V<&S>, got (V<&dyn Tr>,)
+  //^^^^expected V<&'? S>, got (V<&'? dyn Tr>,)
 }
         "#,
     );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs
index 119de7f..def06f2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/diagnostics.rs
@@ -8,7 +8,7 @@
         r#"
 fn test() -> &'static str {
     5
-  //^ expected &str, got i32
+  //^ expected &'static str, got i32
 }
 "#,
     );
@@ -21,7 +21,7 @@
 fn test(x: bool) -> &'static str {
     if x {
         return 1;
-             //^ expected &str, got i32
+             //^ expected &'static str, got i32
     }
     "ok"
 }
@@ -38,7 +38,7 @@
         return "ok";
     }
     1
-  //^ expected &str, got i32
+  //^ expected &'static str, got i32
 }
 "#,
     );
@@ -53,7 +53,7 @@
         "ok"
     } else {
         1
-      //^ expected &str, got i32
+      //^ expected &'static str, got i32
     }
 }
 "#,
@@ -67,7 +67,7 @@
 fn test(x: bool) -> &'static str {
     if x {
         1
-      //^ expected &str, got i32
+      //^ expected &'static str, got i32
     } else {
         "ok"
     }
@@ -83,10 +83,10 @@
 fn test(x: bool) {
     if x {
         "notok"
-      //^^^^^^^ expected (), got &str
+      //^^^^^^^ expected (), got &'static str
     } else {
         "ok"
-      //^^^^ expected (), got &str
+      //^^^^ expected (), got &'static str
     }
     match x { true => true, false => 0 }
   //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected (), got bool
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
index e8369ca..60c03b5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/display_source_code.rs
@@ -67,11 +67,11 @@
 
 fn test(
     _: &(dyn A<Assoc = ()> + Send),
-  //^ &(dyn A<Assoc = ()> + Send)
+  //^ &'_ (dyn A<Assoc = ()> + Send)
     _: &(dyn Send + A<Assoc = ()>),
-  //^ &(dyn A<Assoc = ()> + Send)
+  //^ &'_ (dyn A<Assoc = ()> + Send)
     _: &dyn B<Assoc = ()>,
-  //^ &(dyn B<Assoc = ()>)
+  //^ &'_ (dyn B<Assoc = ()>)
 ) {}
         "#,
     );
@@ -85,7 +85,7 @@
 trait Foo<'a> {}
 
 fn foo(foo: &dyn for<'a> Foo<'a>) {}
-    // ^^^ &dyn Foo<'_>
+    // ^^^ &'_ dyn Foo<'_>
 "#,
     );
 }
@@ -111,11 +111,11 @@
     b;
   //^ impl Foo
     c;
-  //^ &impl Foo + ?Sized
+  //^ &'_ impl Foo + ?Sized
     d;
   //^ S<impl Foo>
     ref_any;
-  //^^^^^^^ &impl ?Sized
+  //^^^^^^^ &'_ impl ?Sized
     empty;
 } //^^^^^ impl Sized
 "#,
@@ -192,7 +192,7 @@
     b;
   //^ fn(impl Foo) -> impl Foo
     c;
-} //^ fn(&impl Foo + ?Sized) -> &impl Foo + ?Sized
+} //^ fn(&'_ impl Foo + ?Sized) -> &'_ impl Foo + ?Sized
 "#,
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
index 2f75338..a0899cb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
@@ -200,8 +200,8 @@
             100..119 'for _ ...!() {}': IntoIterator::IntoIter<isize>
             100..119 'for _ ...!() {}': !
             100..119 'for _ ...!() {}': IntoIterator::IntoIter<isize>
-            100..119 'for _ ...!() {}': &mut IntoIterator::IntoIter<isize>
-            100..119 'for _ ...!() {}': fn next<IntoIterator::IntoIter<isize>>(&mut IntoIterator::IntoIter<isize>) -> Option<<IntoIterator::IntoIter<isize> as Iterator>::Item>
+            100..119 'for _ ...!() {}': &'? mut IntoIterator::IntoIter<isize>
+            100..119 'for _ ...!() {}': fn next<IntoIterator::IntoIter<isize>>(&'? mut IntoIterator::IntoIter<isize>) -> Option<<IntoIterator::IntoIter<isize> as Iterator>::Item>
             100..119 'for _ ...!() {}': Option<IntoIterator::Item<isize>>
             100..119 'for _ ...!() {}': ()
             100..119 'for _ ...!() {}': ()
@@ -221,7 +221,7 @@
             281..303 'Spam {...m!() }': {unknown}
             309..325 'spam!(...am!()]': {unknown}
             350..366 'spam!(... usize': usize
-            372..380 '&spam!()': &isize
+            372..380 '&spam!()': &'? isize
             386..394 '-spam!()': isize
             400..416 'spam!(...pam!()': {unknown}
             422..439 'spam!(...pam!()': isize
@@ -293,8 +293,8 @@
             114..133 'for _ ...!() {}': IntoIterator::IntoIter<isize>
             114..133 'for _ ...!() {}': !
             114..133 'for _ ...!() {}': IntoIterator::IntoIter<isize>
-            114..133 'for _ ...!() {}': &mut IntoIterator::IntoIter<isize>
-            114..133 'for _ ...!() {}': fn next<IntoIterator::IntoIter<isize>>(&mut IntoIterator::IntoIter<isize>) -> Option<<IntoIterator::IntoIter<isize> as Iterator>::Item>
+            114..133 'for _ ...!() {}': &'? mut IntoIterator::IntoIter<isize>
+            114..133 'for _ ...!() {}': fn next<IntoIterator::IntoIter<isize>>(&'? mut IntoIterator::IntoIter<isize>) -> Option<<IntoIterator::IntoIter<isize> as Iterator>::Item>
             114..133 'for _ ...!() {}': Option<IntoIterator::Item<isize>>
             114..133 'for _ ...!() {}': ()
             114..133 'for _ ...!() {}': ()
@@ -314,7 +314,7 @@
             295..317 'Spam {...m!() }': {unknown}
             323..339 'spam!(...am!()]': {unknown}
             364..380 'spam!(... usize': usize
-            386..394 '&spam!()': &isize
+            386..394 '&spam!()': &'? isize
             400..408 '-spam!()': isize
             414..430 'spam!(...pam!()': {unknown}
             436..453 'spam!(...pam!()': isize
@@ -539,7 +539,7 @@
     let msg = foo::Message(foo::MessageRef);
     let r = msg.deref();
     r;
-  //^ &MessageRef
+  //^ &'? MessageRef
 }
 
 //- /lib.rs crate:foo
@@ -703,9 +703,9 @@
         }
         "#,
         expect![[r#"
-            !0..2 '""': &str
+            !0..2 '""': &'static str
             63..87 '{     ...!(); }': ()
-            73..74 'x': &str
+            73..74 'x': &'static str
         "#]],
     );
 }
@@ -741,9 +741,9 @@
         }
         "#,
         expect![[r#"
-            !0..13 '"helloworld!"': &str
+            !0..13 '"helloworld!"': &'static str
             65..121 '{     ...")); }': ()
-            75..76 'x': &str
+            75..76 'x': &'static str
         "#]],
     );
 }
@@ -820,7 +820,7 @@
 fn main() {
     let a = include_str!("foo.rs");
     a;
-} //^ &str
+} //^ &'static str
 
 //- /foo.rs
 hello
@@ -847,7 +847,7 @@
 fn main() {
     let a = include_str!(m!(".rs"));
     a;
-} //^ &str
+} //^ &'static str
 
 //- /foo.rs
 hello
@@ -960,9 +960,9 @@
         }
         "#,
         expect![[r#"
-            !0..13 '"helloworld!"': &str
+            !0..13 '"helloworld!"': &'static str
             103..160 '{     ...")); }': ()
-            113..114 'x': &str
+            113..114 'x': &'static str
         "#]],
     );
 }
@@ -977,7 +977,7 @@
 
         fn main() {
             let x = env!("foo");
-              //^ &str
+              //^ &'static str
         }
         "#,
     );
@@ -991,7 +991,7 @@
 //- /main.rs env:foo=bar
 fn main() {
     let x = option_env!("foo");
-      //^ Option<&str>
+      //^ Option<&'static str>
 }
         "#,
     );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
index 8609ba4..63a83d4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
@@ -658,7 +658,7 @@
         }
         "#,
         expect![[r#"
-            29..33 'self': &Self
+            29..33 'self': &'? Self
             63..64 't': T
             69..88 '{     ...d(); }': ()
             75..76 't': T
@@ -679,7 +679,7 @@
         }
         "#,
         expect![[r#"
-            32..36 'self': &Self
+            32..36 'self': &'? Self
             70..71 't': T
             76..95 '{     ...d(); }': ()
             82..83 't': T
@@ -757,7 +757,7 @@
 impl Clone for S {}
 impl Clone for &S {}
 fn test() { (S.clone(), (&S).clone(), (&&S).clone()); }
-          //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &S)
+          //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (S, S, &'? S)
 "#,
     );
 }
@@ -1150,12 +1150,12 @@
         }
         "#,
         expect![[r#"
-            51..55 'self': &Self
+            51..55 'self': &'? Self
             64..69 '{ 0 }': u32
             66..67 '0': u32
-            176..177 'd': &dyn Trait
+            176..177 'd': &'? dyn Trait
             191..207 '{     ...o(); }': ()
-            197..198 'd': &dyn Trait
+            197..198 'd': &'? dyn Trait
             197..204 'd.foo()': u32
         "#]],
     );
@@ -1182,15 +1182,15 @@
 }
 "#,
         expect![[r#"
-            75..79 'self': &S
+            75..79 'self': &'? S
             89..109 '{     ...     }': bool
             99..103 'true': bool
             123..167 '{     ...o(); }': ()
-            133..134 's': &S
-            137..151 'unsafe { f() }': &S
-            146..147 'f': fn f() -> &S
-            146..149 'f()': &S
-            157..158 's': &S
+            133..134 's': &'? S
+            137..151 'unsafe { f() }': &'static S
+            146..147 'f': fn f() -> &'static S
+            146..149 'f()': &'static S
+            157..158 's': &'? S
             157..164 's.foo()': bool
         "#]],
     );
@@ -1601,11 +1601,11 @@
 fn f() {
     let v = [4].into_iter();
     v;
-  //^ &i32
+  //^ &'? i32
 
     let a = [0, 1].into_iter();
     a;
-  //^ &i32
+  //^ &'? i32
 }
 
 //- /main2021.rs crate:main2021 deps:core edition:2021
@@ -1618,7 +1618,7 @@
 
     let a = [0, 1].into_iter();
     a;
-  //^ &i32
+  //^ &'? i32
 }
 
 //- /core.rs crate:core
@@ -1767,7 +1767,7 @@
     let a2 = A(make(), 1i32);
     let _: &str = a2.thing();
     a2;
-  //^^ A<C<&str>, i32>
+  //^^ A<C<&'? str>, i32>
 }
 "#,
     );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
index 5d809b8..0ccbcf6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/never_type.rs
@@ -104,7 +104,7 @@
 fn test() {
     let a = if true { Option::None } else { Option::Some(return) };
     a;
-  //^ Option<&str>
+  //^ Option<&'static str>
     match 42 {
         42 => a,
         _ => Option::Some("str"),
@@ -317,8 +317,8 @@
             63..81 '{ loop...foo" }': u32
             65..72 'loop {}': !
             70..72 '{}': ()
-            74..79 '"foo"': &str
-            74..79: expected u32, got &str
+            74..79 '"foo"': &'static str
+            74..79: expected u32, got &'static str
         "#]],
     );
 }
@@ -365,8 +365,8 @@
             151..172 'for a ...eak; }': {unknown}
             151..172 'for a ...eak; }': !
             151..172 'for a ...eak; }': {unknown}
-            151..172 'for a ...eak; }': &mut {unknown}
-            151..172 'for a ...eak; }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
+            151..172 'for a ...eak; }': &'? mut {unknown}
+            151..172 'for a ...eak; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
             151..172 'for a ...eak; }': Option<{unknown}>
             151..172 'for a ...eak; }': ()
             151..172 'for a ...eak; }': ()
@@ -381,8 +381,8 @@
             237..250 'for a in b {}': {unknown}
             237..250 'for a in b {}': !
             237..250 'for a in b {}': {unknown}
-            237..250 'for a in b {}': &mut {unknown}
-            237..250 'for a in b {}': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
+            237..250 'for a in b {}': &'? mut {unknown}
+            237..250 'for a in b {}': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
             237..250 'for a in b {}': Option<{unknown}>
             237..250 'for a in b {}': ()
             237..250 'for a in b {}': ()
@@ -396,8 +396,8 @@
             315..337 'for a ...urn; }': {unknown}
             315..337 'for a ...urn; }': !
             315..337 'for a ...urn; }': {unknown}
-            315..337 'for a ...urn; }': &mut {unknown}
-            315..337 'for a ...urn; }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
+            315..337 'for a ...urn; }': &'? mut {unknown}
+            315..337 'for a ...urn; }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
             315..337 'for a ...urn; }': Option<{unknown}>
             315..337 'for a ...urn; }': ()
             315..337 'for a ...urn; }': ()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
index 4355881..5e040a6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/patterns.rs
@@ -32,27 +32,27 @@
         }
         "#,
         expect![[r#"
-            8..9 'x': &i32
+            8..9 'x': &'? i32
             17..400 '{     ...o_x; }': ()
-            27..28 'y': &i32
-            31..32 'x': &i32
-            42..44 '&z': &i32
+            27..28 'y': &'? i32
+            31..32 'x': &'? i32
+            42..44 '&z': &'? i32
             43..44 'z': i32
-            47..48 'x': &i32
+            47..48 'x': &'? i32
             58..59 'a': i32
             62..63 'z': i32
-            73..79 '(c, d)': (i32, &str)
+            73..79 '(c, d)': (i32, &'static str)
             74..75 'c': i32
-            77..78 'd': &str
-            82..94 '(1, "hello")': (i32, &str)
+            77..78 'd': &'static str
+            82..94 '(1, "hello")': (i32, &'static str)
             83..84 '1': i32
-            86..93 '"hello"': &str
+            86..93 '"hello"': &'static str
             101..151 'for (e...     }': fn into_iter<{unknown}>({unknown}) -> <{unknown} as IntoIterator>::IntoIter
             101..151 'for (e...     }': {unknown}
             101..151 'for (e...     }': !
             101..151 'for (e...     }': {unknown}
-            101..151 'for (e...     }': &mut {unknown}
-            101..151 'for (e...     }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
+            101..151 'for (e...     }': &'? mut {unknown}
+            101..151 'for (e...     }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
             101..151 'for (e...     }': Option<({unknown}, {unknown})>
             101..151 'for (e...     }': ()
             101..151 'for (e...     }': ()
@@ -74,10 +74,10 @@
             194..197 'val': {unknown}
             210..236 'if let...rue {}': ()
             213..233 'let x ... &true': bool
-            217..225 'x @ true': &bool
+            217..225 'x @ true': &'? bool
             221..225 'true': bool
             221..225 'true': bool
-            228..233 '&true': &bool
+            228..233 '&true': &'? bool
             229..233 'true': bool
             234..236 '{}': ()
             246..252 'lambda': impl Fn(u64, u64, i32) -> i32
@@ -90,14 +90,14 @@
             277..282 'a + b': u64
             281..282 'b': u64
             284..285 'c': i32
-            298..310 'ref ref_to_x': &&i32
-            313..314 'x': &i32
-            324..333 'mut mut_x': &i32
-            336..337 'x': &i32
-            347..367 'ref mu...f_to_x': &mut &i32
-            370..371 'x': &i32
-            381..382 'k': &mut &i32
-            385..397 'mut_ref_to_x': &mut &i32
+            298..310 'ref ref_to_x': &'? &'? i32
+            313..314 'x': &'? i32
+            324..333 'mut mut_x': &'? i32
+            336..337 'x': &'? i32
+            347..367 'ref mu...f_to_x': &'? mut &'? i32
+            370..371 'x': &'? i32
+            381..382 'k': &'? mut &'? i32
+            385..397 'mut_ref_to_x': &'? mut &'? i32
         "#]],
     );
 }
@@ -120,14 +120,14 @@
             17..28 '{ loop {} }': T
             19..26 'loop {}': !
             24..26 '{}': ()
-            37..38 'x': &i32
+            37..38 'x': &'? i32
             46..208 '{     ...) {} }': ()
             52..75 'if let...y() {}': ()
             55..72 'let "f... any()': bool
-            59..64 '"foo"': &str
-            59..64 '"foo"': &str
-            67..70 'any': fn any<&str>() -> &str
-            67..72 'any()': &str
+            59..64 '"foo"': &'static str
+            59..64 '"foo"': &'static str
+            67..70 'any': fn any<&'static str>() -> &'static str
+            67..72 'any()': &'static str
             73..75 '{}': ()
             80..99 'if let...y() {}': ()
             83..96 'let 1 = any()': bool
@@ -178,7 +178,7 @@
         }
         "#,
         expect![[r#"
-            8..9 'x': &i32
+            8..9 'x': &'? i32
             17..75 '{     ...2 {} }': ()
             23..45 'if let...u32 {}': ()
             26..42 'let 1....= 2u32': bool
@@ -208,14 +208,14 @@
         expect![[r#"
             27..78 '{     ...(1); }': ()
             37..41 'A(n)': A<i32>
-            39..40 'n': &i32
-            44..49 '&A(1)': &A<i32>
+            39..40 'n': &'? i32
+            44..49 '&A(1)': &'? A<i32>
             45..46 'A': extern "rust-call" A<i32>(i32) -> A<i32>
             45..49 'A(1)': A<i32>
             47..48 '1': i32
             59..63 'A(n)': A<i32>
-            61..62 'n': &mut i32
-            66..75 '&mut A(1)': &mut A<i32>
+            61..62 'n': &'? mut i32
+            66..75 '&mut A(1)': &'? mut A<i32>
             71..72 'A': extern "rust-call" A<i32>(i32) -> A<i32>
             71..75 'A(1)': A<i32>
             73..74 '1': i32
@@ -235,17 +235,17 @@
         "#,
         expect![[r#"
             10..56 '{     ...= v; }': ()
-            20..21 'v': &(i32, &i32)
-            24..32 '&(1, &2)': &(i32, &i32)
-            25..32 '(1, &2)': (i32, &i32)
+            20..21 'v': &'? (i32, &'? i32)
+            24..32 '&(1, &2)': &'? (i32, &'? i32)
+            25..32 '(1, &2)': (i32, &'? i32)
             26..27 '1': i32
-            29..31 '&2': &i32
+            29..31 '&2': &'? i32
             30..31 '2': i32
-            42..49 '(_, &w)': (i32, &i32)
+            42..49 '(_, &w)': (i32, &'? i32)
             43..44 '_': i32
-            46..48 '&w': &i32
+            46..48 '&w': &'? i32
             47..48 'w': i32
-            52..53 'v': &(i32, &i32)
+            52..53 'v': &'? (i32, &'? i32)
         "#]],
     );
 }
@@ -286,28 +286,28 @@
         "#,
         expect![[r#"
             10..209 '{     ...   } }': ()
-            20..25 'slice': &[f64]
-            36..42 '&[0.0]': &[f64; 1]
+            20..25 'slice': &'? [f64]
+            36..42 '&[0.0]': &'? [f64; 1]
             37..42 '[0.0]': [f64; 1]
             38..41 '0.0': f64
             48..207 'match ...     }': ()
-            54..59 'slice': &[f64]
-            70..73 '&[]': &[f64]
+            54..59 'slice': &'? [f64]
+            70..73 '&[]': &'? [f64]
             71..73 '[]': [f64]
             77..79 '{}': ()
-            89..93 '&[a]': &[f64]
+            89..93 '&[a]': &'? [f64]
             90..93 '[a]': [f64]
             91..92 'a': f64
             97..123 '{     ...     }': ()
             111..112 'a': f64
-            133..140 '&[b, c]': &[f64]
+            133..140 '&[b, c]': &'? [f64]
             134..140 '[b, c]': [f64]
             135..136 'b': f64
             138..139 'c': f64
             144..185 '{     ...     }': ()
             158..159 'b': f64
             173..174 'c': f64
-            194..195 '_': &[f64]
+            194..195 '_': &'? [f64]
             199..201 '{}': ()
         "#]],
     );
@@ -327,14 +327,14 @@
         "#,
         expect![[r#"
             10..98 '{     ...   } }': ()
-            20..21 's': &str
-            30..37 '"hello"': &str
+            20..21 's': &'? str
+            30..37 '"hello"': &'static str
             43..96 'match ...     }': ()
-            49..50 's': &str
-            61..68 '"hello"': &str
-            61..68 '"hello"': &str
+            49..50 's': &'? str
+            61..68 '"hello"': &'static str
+            61..68 '"hello"': &'static str
             72..74 '{}': ()
-            83..84 '_': &str
+            83..84 '_': &'? str
             88..90 '{}': ()
         "#]],
     );
@@ -358,27 +358,27 @@
         }
         "#,
         expect![[r#"
-            105..109 'self': &[T; N]
+            105..109 'self': &'? [T; N]
             111..116 'index': {unknown}
-            157..180 '{     ...     }': &[u8]
+            157..180 '{     ...     }': &'? [u8]
             167..174 'loop {}': !
             172..174 '{}': ()
             191..192 'v': [u8; 3]
             203..261 '{     ...v {} }': ()
             209..233 'if let...[S] {}': ()
             212..230 'let b"... &v[S]': bool
-            216..222 'b"foo"': &[u8]
-            216..222 'b"foo"': &[u8]
-            225..230 '&v[S]': &[u8]
+            216..222 'b"foo"': &'static [u8]
+            216..222 'b"foo"': &'static [u8]
+            225..230 '&v[S]': &'? [u8]
             226..227 'v': [u8; 3]
             226..230 'v[S]': [u8]
             228..229 'S': S
             231..233 '{}': ()
             238..259 'if let... &v {}': ()
             241..256 'let b"foo" = &v': bool
-            245..251 'b"foo"': &[u8; 3]
-            245..251 'b"foo"': &[u8; 3]
-            254..256 '&v': &[u8; 3]
+            245..251 'b"foo"': &'static [u8; 3]
+            245..251 'b"foo"': &'static [u8; 3]
+            254..256 '&v': &'? [u8; 3]
             255..256 'v': [u8; 3]
             257..259 '{}': ()
         "#]],
@@ -399,17 +399,17 @@
         "#,
         expect![[r#"
             10..108 '{     ...   } }': ()
-            20..21 's': &str
-            30..37 '"hello"': &str
+            20..21 's': &'? str
+            30..37 '"hello"': &'static str
             43..106 'match ...     }': ()
-            49..50 's': &str
-            61..68 '"hello"': &str
-            61..68 '"hello"': &str
-            61..78 '"hello...world"': &str
-            71..78 '"world"': &str
-            71..78 '"world"': &str
+            49..50 's': &'? str
+            61..68 '"hello"': &'static str
+            61..68 '"hello"': &'static str
+            61..78 '"hello...world"': &'? str
+            71..78 '"world"': &'static str
+            71..78 '"world"': &'static str
             82..84 '{}': ()
-            93..94 '_': &str
+            93..94 '_': &'? str
             98..100 '{}': ()
         "#]],
     );
@@ -505,10 +505,10 @@
             216..217 '1': usize
             227..231 'E::B': E
             235..237 '10': usize
-            255..274 'ref d ...{ .. }': &E
+            255..274 'ref d ...{ .. }': &'? E
             263..274 'E::A { .. }': E
             277..278 'e': E
-            284..285 'd': &E
+            284..285 'd': &'? E
         "#]],
     );
 }
@@ -529,14 +529,14 @@
         expect![[r#"
             42..151 '{     ...     }': ()
             56..64 'Self(s,)': Foo
-            61..62 's': &usize
-            67..75 '&Foo(0,)': &Foo
+            61..62 's': &'? usize
+            67..75 '&Foo(0,)': &'? Foo
             68..71 'Foo': extern "rust-call" Foo(usize) -> Foo
             68..75 'Foo(0,)': Foo
             72..73 '0': usize
             89..97 'Self(s,)': Foo
-            94..95 's': &mut usize
-            100..112 '&mut Foo(0,)': &mut Foo
+            94..95 's': &'? mut usize
+            100..112 '&mut Foo(0,)': &'? mut Foo
             105..108 'Foo': extern "rust-call" Foo(usize) -> Foo
             105..112 'Foo(0,)': Foo
             109..110 '0': usize
@@ -669,7 +669,7 @@
 }
         "#,
         expect![[r#"
-            27..31 'self': &S
+            27..31 'self': &'? S
             41..50 '{ false }': bool
             43..48 'false': bool
             64..115 '{     ...   } }': ()
@@ -679,7 +679,7 @@
             93..94 's': S
             93..100 's.foo()': bool
             104..106 '()': ()
-    "#]],
+        "#]],
     )
 }
 
@@ -702,29 +702,29 @@
             51..58 'loop {}': !
             56..58 '{}': ()
             72..171 '{     ... x); }': ()
-            78..81 'foo': fn foo<&(i32, &str), i32, impl FnOnce(&(i32, &str)) -> i32>(&(i32, &str), impl FnOnce(&(i32, &str)) -> i32) -> i32
+            78..81 'foo': fn foo<&'? (i32, &'? str), i32, impl FnOnce(&'? (i32, &'? str)) -> i32>(&'? (i32, &'? str), impl FnOnce(&'? (i32, &'? str)) -> i32) -> i32
             78..105 'foo(&(...y)| x)': i32
-            82..91 '&(1, "a")': &(i32, &str)
-            83..91 '(1, "a")': (i32, &str)
+            82..91 '&(1, "a")': &'? (i32, &'static str)
+            83..91 '(1, "a")': (i32, &'static str)
             84..85 '1': i32
-            87..90 '"a"': &str
-            93..104 '|&(x, y)| x': impl FnOnce(&(i32, &str)) -> i32
-            94..101 '&(x, y)': &(i32, &str)
-            95..101 '(x, y)': (i32, &str)
+            87..90 '"a"': &'static str
+            93..104 '|&(x, y)| x': impl FnOnce(&'? (i32, &'? str)) -> i32
+            94..101 '&(x, y)': &'? (i32, &'? str)
+            95..101 '(x, y)': (i32, &'? str)
             96..97 'x': i32
-            99..100 'y': &str
+            99..100 'y': &'? str
             103..104 'x': i32
-            142..145 'foo': fn foo<&(i32, &str), &i32, impl FnOnce(&(i32, &str)) -> &i32>(&(i32, &str), impl FnOnce(&(i32, &str)) -> &i32) -> &i32
-            142..168 'foo(&(...y)| x)': &i32
-            146..155 '&(1, "a")': &(i32, &str)
-            147..155 '(1, "a")': (i32, &str)
+            142..145 'foo': fn foo<&'? (i32, &'? str), &'? i32, impl FnOnce(&'? (i32, &'? str)) -> &'? i32>(&'? (i32, &'? str), impl FnOnce(&'? (i32, &'? str)) -> &'? i32) -> &'? i32
+            142..168 'foo(&(...y)| x)': &'? i32
+            146..155 '&(1, "a")': &'? (i32, &'static str)
+            147..155 '(1, "a")': (i32, &'static str)
             148..149 '1': i32
-            151..154 '"a"': &str
-            157..167 '|(x, y)| x': impl FnOnce(&(i32, &str)) -> &i32
-            158..164 '(x, y)': (i32, &str)
-            159..160 'x': &i32
-            162..163 'y': &&str
-            166..167 'x': &i32
+            151..154 '"a"': &'static str
+            157..167 '|(x, y)| x': impl FnOnce(&'? (i32, &'? str)) -> &'? i32
+            158..164 '(x, y)': (i32, &'? str)
+            159..160 'x': &'? i32
+            162..163 'y': &'? &'? str
+            166..167 'x': &'? i32
         "#]],
     );
 }
@@ -741,13 +741,13 @@
         }
         "#,
         expect![[r#"
-            7..13 'params': &[i32]
+            7..13 'params': &'? [i32]
             23..92 '{     ...   } }': ()
             29..90 'match ...     }': ()
-            35..41 'params': &[i32]
+            35..41 'params': &'? [i32]
             52..69 '[head,... @ ..]': [i32]
-            53..57 'head': &i32
-            59..68 'tail @ ..': &[i32]
+            53..57 'head': &'? i32
+            59..68 'tail @ ..': &'? [i32]
             66..68 '..': [i32]
             73..84 '{         }': ()
         "#]],
@@ -1109,7 +1109,7 @@
 #[lang = "va_list"]
 pub struct VaListImpl<'f>;
 fn my_fn(foo: ...) {}
-       //^^^ VaListImpl<'{error}>
+       //^^^ VaListImpl<'?>
 "#,
     );
 }
@@ -1122,9 +1122,9 @@
     let &() = &();
     let &mut () = &mut ();
     let &mut () = &();
-      //^^^^^^^ expected &(), got &mut ()
+      //^^^^^^^ expected &'? (), got &'? mut ()
     let &() = &mut ();
-      //^^^ expected &mut (), got &()
+      //^^^ expected &'? mut (), got &'? ()
 }
 "#,
     );
@@ -1148,7 +1148,7 @@
     };
 
     if let Wrap::<X>::A { cool, ..} = &wrapped {}
-                        //^^^^ &u32
+                        //^^^^ &'? u32
 }
 "#,
     );
@@ -1182,7 +1182,7 @@
     };
 
     if let Wrap::<<S as Schematic>::Props>::A { cool, ..} = &wrapped {}
-                                              //^^^^ &u32
+                                              //^^^^ &'? u32
 }
 "#,
     );
@@ -1217,7 +1217,7 @@
     match &6 {
         Foo::<i32>::TEST_I32_REF => (),
         Foo::<i32>::TEST_I32 => (),
-      //^^^^^^^^^^^^^^^^^^^^ expected &i32, got i32
+      //^^^^^^^^^^^^^^^^^^^^ expected &'? i32, got i32
         _ => (),
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index c2d2047..3aa94be 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -99,7 +99,7 @@
             24..31 'unknown': {unknown}
             37..44 '[y, &y]': [{unknown}; 2]
             38..39 'y': {unknown}
-            41..43 '&y': &{unknown}
+            41..43 '&y': &'? {unknown}
             42..43 'y': {unknown}
         "#]],
     );
@@ -117,19 +117,19 @@
         "#,
         expect![[r#"
             10..79 '{     ...x)]; }': ()
-            20..21 'x': &{unknown}
-            24..31 'unknown': &{unknown}
+            20..21 'x': &'? {unknown}
+            24..31 'unknown': &'? {unknown}
             41..42 'y': {unknown}
             45..52 'unknown': {unknown}
-            58..76 '[(x, y..., &x)]': [(&{unknown}, {unknown}); 2]
-            59..65 '(x, y)': (&{unknown}, {unknown})
-            60..61 'x': &{unknown}
+            58..76 '[(x, y..., &x)]': [(&'? {unknown}, {unknown}); 2]
+            59..65 '(x, y)': (&'? {unknown}, {unknown})
+            60..61 'x': &'? {unknown}
             63..64 'y': {unknown}
-            67..75 '(&y, &x)': (&{unknown}, {unknown})
-            68..70 '&y': &{unknown}
+            67..75 '(&y, &x)': (&'? {unknown}, {unknown})
+            68..70 '&y': &'? {unknown}
             69..70 'y': {unknown}
-            72..74 '&x': &&{unknown}
-            73..74 'x': &{unknown}
+            72..74 '&x': &'? &'? {unknown}
+            73..74 'x': &'? {unknown}
         "#]],
     );
 }
@@ -166,7 +166,7 @@
             59..136 'match ...     }': ()
             65..82 'someth...nknown': Maybe<{unknown}>
             93..123 'Maybe:...thing)': Maybe<{unknown}>
-            105..122 'ref mu...ething': &mut {unknown}
+            105..122 'ref mu...ething': &'? mut {unknown}
             127..129 '()': ()
         "#]],
     );
@@ -183,7 +183,7 @@
         "#,
         expect![[r#"
             22..52 '{     ...n']; }': ()
-            28..49 '&[0, b...b'\n']': &[u8; 4]
+            28..49 '&[0, b...b'\n']': &'? [u8; 4]
             29..49 '[0, b'...b'\n']': [u8; 4]
             30..31 '0': u8
             33..38 'b'\n'': u8
@@ -269,8 +269,8 @@
             32..320 'for co...     }': {unknown}
             32..320 'for co...     }': !
             32..320 'for co...     }': {unknown}
-            32..320 'for co...     }': &mut {unknown}
-            32..320 'for co...     }': fn next<{unknown}>(&mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
+            32..320 'for co...     }': &'? mut {unknown}
+            32..320 'for co...     }': fn next<{unknown}>(&'? mut {unknown}) -> Option<<{unknown} as Iterator>::Item>
             32..320 'for co...     }': Option<{unknown}>
             32..320 'for co...     }': ()
             32..320 'for co...     }': ()
@@ -278,22 +278,22 @@
             36..43 'content': {unknown}
             47..60 'doesnt_matter': {unknown}
             61..320 '{     ...     }': ()
-            75..79 'name': &{unknown}
-            82..166 'if doe...     }': &{unknown}
+            75..79 'name': &'? {unknown}
+            82..166 'if doe...     }': &'? {unknown}
             85..98 'doesnt_matter': bool
-            99..128 '{     ...     }': &{unknown}
-            113..118 'first': &{unknown}
-            134..166 '{     ...     }': &{unknown}
-            148..156 '&content': &{unknown}
+            99..128 '{     ...     }': &'? {unknown}
+            113..118 'first': &'? {unknown}
+            134..166 '{     ...     }': &'? {unknown}
+            148..156 '&content': &'? {unknown}
             149..156 'content': {unknown}
-            181..188 'content': &{unknown}
-            191..313 'if ICE...     }': &{unknown}
+            181..188 'content': &'? {unknown}
+            191..313 'if ICE...     }': &'? {unknown}
             194..231 'ICE_RE..._VALUE': {unknown}
             194..247 'ICE_RE...&name)': bool
-            241..246 '&name': &&{unknown}
-            242..246 'name': &{unknown}
-            248..276 '{     ...     }': &{unknown}
-            262..266 'name': &{unknown}
+            241..246 '&name': &'? &'? {unknown}
+            242..246 'name': &'? {unknown}
+            248..276 '{     ...     }': &'? {unknown}
+            262..266 'name': &'? {unknown}
             282..313 '{     ...     }': {unknown}
             296..303 'content': {unknown}
         "#]],
@@ -318,7 +318,7 @@
         expect![[r#"
             91..105 'query_response': Canonical<QueryResponse<R>>
             136..166 '{     ...lue; }': ()
-            142..163 '&query....value': &QueryResponse<R>
+            142..163 '&query....value': &'? QueryResponse<R>
             143..157 'query_response': Canonical<QueryResponse<R>>
             143..163 'query_....value': QueryResponse<R>
         "#]],
@@ -465,12 +465,12 @@
         }
         "#,
         expect![[r#"
-            7..13 'params': &[usize]
+            7..13 'params': &'? [usize]
             25..80 '{     ...   } }': ()
             31..78 'match ...     }': ()
-            37..43 'params': &[usize]
+            37..43 'params': &'? [usize]
             54..66 '[ps @ .., _]': [usize]
-            55..62 'ps @ ..': &[usize]
+            55..62 'ps @ ..': &'? [usize]
             60..62 '..': [usize]
             64..65 '_': usize
             70..72 '{}': ()
@@ -523,13 +523,13 @@
         "#,
         expect![[r#"
             31..37 'FOO {}': FOO
-            63..67 'self': &FOO
+            63..67 'self': &'? FOO
             69..71 '{}': ()
             85..119 '{     ...o(); }': ()
-            95..96 'a': &FOO
-            99..103 '&FOO': &FOO
+            95..96 'a': &'? FOO
+            99..103 '&FOO': &'? FOO
             100..103 'FOO': FOO
-            109..110 'a': &FOO
+            109..110 'a': &'? FOO
             109..116 'a.foo()': ()
         "#]],
     );
@@ -715,12 +715,12 @@
         }
         "#,
         expect![[r#"
-            70..73 'key': &K
+            70..73 'key': &'? K
             132..148 '{     ...key) }': impl Future<Output = <K as Foo<R>>::Bar>
-            138..141 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar>
+            138..141 'bar': fn bar<R, K>(&'? K) -> impl Future<Output = <K as Foo<R>>::Bar>
             138..146 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar>
-            142..145 'key': &K
-            162..165 'key': &K
+            142..145 'key': &'? K
+            162..165 'key': &'? K
             224..227 '{ }': ()
         "#]],
     );
@@ -771,11 +771,11 @@
         }
         "#,
         expect![[r#"
-            379..383 'self': &mut PeerSet<D>
+            379..383 'self': &'? mut PeerSet<D>
             401..424 '{     ...     }': dyn Future<Output = ()>
             411..418 'loop {}': !
             416..418 '{}': ()
-            575..579 'self': &mut Self
+            575..579 'self': &'? mut Self
         "#]],
     );
 }
@@ -815,19 +815,19 @@
             225..229 'iter': T
             244..246 '{}': Vec<A>
             258..402 '{     ...r(); }': ()
-            268..273 'inner': Map<impl Fn(&f64) -> f64>
-            276..300 'Map { ... 0.0 }': Map<impl Fn(&f64) -> f64>
-            285..298 '|_: &f64| 0.0': impl Fn(&f64) -> f64
-            286..287 '_': &f64
+            268..273 'inner': Map<impl Fn(&'? f64) -> f64>
+            276..300 'Map { ... 0.0 }': Map<impl Fn(&'? f64) -> f64>
+            285..298 '|_: &f64| 0.0': impl Fn(&'? f64) -> f64
+            286..287 '_': &'? f64
             295..298 '0.0': f64
-            311..317 'repeat': Repeat<Map<impl Fn(&f64) -> f64>>
-            320..345 'Repeat...nner }': Repeat<Map<impl Fn(&f64) -> f64>>
-            338..343 'inner': Map<impl Fn(&f64) -> f64>
-            356..359 'vec': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>>
-            362..371 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>, Repeat<Map<impl Fn(&f64) -> f64>>>(Repeat<Map<impl Fn(&f64) -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>>
-            362..379 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>>
-            372..378 'repeat': Repeat<Map<impl Fn(&f64) -> f64>>
-            386..389 'vec': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&f64) -> f64>>>>
+            311..317 'repeat': Repeat<Map<impl Fn(&'? f64) -> f64>>
+            320..345 'Repeat...nner }': Repeat<Map<impl Fn(&'? f64) -> f64>>
+            338..343 'inner': Map<impl Fn(&'? f64) -> f64>
+            356..359 'vec': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>>
+            362..371 'from_iter': fn from_iter<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>, Repeat<Map<impl Fn(&'? f64) -> f64>>>(Repeat<Map<impl Fn(&'? f64) -> f64>>) -> Vec<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>>
+            362..379 'from_i...epeat)': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>>
+            372..378 'repeat': Repeat<Map<impl Fn(&'? f64) -> f64>>
+            386..389 'vec': Vec<IntoIterator::Item<Repeat<Map<impl Fn(&'? f64) -> f64>>>>
             386..399 'vec.foo_bar()': {unknown}
         "#]],
     );
@@ -850,10 +850,10 @@
 }
 "#,
         expect![[r#"
-            40..44 'self': &S<T>
+            40..44 'self': &'? S<T>
             46..48 '_t': T
             53..55 '{}': ()
-            81..85 'self': &S<T>
+            81..85 'self': &'? S<T>
             87..89 '_f': F
             94..96 '{}': ()
             109..160 '{     ...10); }': ()
@@ -862,8 +862,8 @@
             123..126 'S()': S<i32>
             132..133 's': S<i32>
             132..144 's.g(|_x| {})': ()
-            136..143 '|_x| {}': impl FnOnce(&i32)
-            137..139 '_x': &i32
+            136..143 '|_x| {}': impl FnOnce(&'? i32)
+            137..139 '_x': &'? i32
             141..143 '{}': ()
             150..151 's': S<i32>
             150..157 's.f(10)': ()
@@ -895,14 +895,14 @@
 }
 "#,
         expect![[r#"
-            123..127 'self': &Mutex<T>
-            150..152 '{}': MutexGuard<'{error}, T>
-            234..238 'self': &{unknown}
+            123..127 'self': &'? Mutex<T>
+            150..152 '{}': MutexGuard<'?, T>
+            234..238 'self': &'? {unknown}
             240..290 '{     ...()); }': ()
-            250..251 'w': &Mutex<BufWriter>
+            250..251 'w': &'? Mutex<BufWriter>
             276..287 '*(w.lock())': BufWriter
-            278..279 'w': &Mutex<BufWriter>
-            278..286 'w.lock()': MutexGuard<'{error}, BufWriter>
+            278..279 'w': &'? Mutex<BufWriter>
+            278..286 'w.lock()': MutexGuard<'?, BufWriter>
         "#]],
     );
 }
@@ -1023,20 +1023,20 @@
         expect![[r#"
             14..53 '{     ...)] 9 }': ()
             20..31 '{ "first" }': ()
-            22..29 '"first"': &str
+            22..29 '"first"': &'static str
             72..190 '{     ...] 13 }': ()
             78..88 '{ "fake" }': ()
-            80..86 '"fake"': &str
+            80..86 '"fake"': &'static str
             93..103 '{ "fake" }': ()
-            95..101 '"fake"': &str
+            95..101 '"fake"': &'static str
             108..120 '{ "second" }': ()
-            110..118 '"second"': &str
+            110..118 '"second"': &'static str
             210..273 '{     ... 15; }': ()
             216..227 '{ "third" }': ()
-            218..225 '"third"': &str
+            218..225 '"third"': &'static str
             293..357 '{     ...] 15 }': ()
-            299..311 '{ "fourth" }': &str
-            301..309 '"fourth"': &str
+            299..311 '{ "fourth" }': &'static str
+            301..309 '"fourth"': &'static str
         "#]],
     )
 }
@@ -1238,8 +1238,8 @@
             16..66 'for _ ...     }': IntoIterator::IntoIter<()>
             16..66 'for _ ...     }': !
             16..66 'for _ ...     }': IntoIterator::IntoIter<()>
-            16..66 'for _ ...     }': &mut IntoIterator::IntoIter<()>
-            16..66 'for _ ...     }': fn next<IntoIterator::IntoIter<()>>(&mut IntoIterator::IntoIter<()>) -> Option<<IntoIterator::IntoIter<()> as Iterator>::Item>
+            16..66 'for _ ...     }': &'? mut IntoIterator::IntoIter<()>
+            16..66 'for _ ...     }': fn next<IntoIterator::IntoIter<()>>(&'? mut IntoIterator::IntoIter<()>) -> Option<<IntoIterator::IntoIter<()> as Iterator>::Item>
             16..66 'for _ ...     }': Option<IntoIterator::Item<()>>
             16..66 'for _ ...     }': ()
             16..66 'for _ ...     }': ()
@@ -1600,85 +1600,6 @@
 }
 
 #[test]
-fn rust_161_option_clone() {
-    check_types(
-        r#"
-//- minicore: option, drop
-
-fn test(o: &Option<i32>) {
-    o.my_clone();
-  //^^^^^^^^^^^^ Option<i32>
-}
-
-pub trait MyClone: Sized {
-    fn my_clone(&self) -> Self;
-}
-
-impl<T> const MyClone for Option<T>
-where
-    T: ~const MyClone + ~const Drop + ~const Destruct,
-{
-    fn my_clone(&self) -> Self {
-        match self {
-            Some(x) => Some(x.my_clone()),
-            None => None,
-        }
-    }
-}
-
-impl const MyClone for i32 {
-    fn my_clone(&self) -> Self {
-        *self
-    }
-}
-
-pub trait Destruct {}
-
-impl<T: ?Sized> const Destruct for T {}
-"#,
-    );
-}
-
-#[test]
-fn rust_162_option_clone() {
-    check_types(
-        r#"
-//- minicore: option, drop
-
-fn test(o: &Option<i32>) {
-    o.my_clone();
-  //^^^^^^^^^^^^ Option<i32>
-}
-
-pub trait MyClone: Sized {
-    fn my_clone(&self) -> Self;
-}
-
-impl<T> const MyClone for Option<T>
-where
-    T: ~const MyClone + ~const Destruct,
-{
-    fn my_clone(&self) -> Self {
-        match self {
-            Some(x) => Some(x.my_clone()),
-            None => None,
-        }
-    }
-}
-
-impl const MyClone for i32 {
-    fn my_clone(&self) -> Self {
-        *self
-    }
-}
-
-#[lang = "destruct"]
-pub trait Destruct {}
-"#,
-    );
-}
-
-#[test]
 fn tuple_struct_pattern_with_unmatched_args_crash() {
     check_infer(
         r#"
@@ -1727,7 +1648,7 @@
         r#"
 fn foo(a: &dyn DoesNotExist) {
     a.bar();
-  //^&{unknown}
+  //^&'? {unknown}
 }
         "#,
     );
@@ -1851,9 +1772,9 @@
     match &E::A {
         b @ (x @ E::A | x) => {
             b;
-          //^ &E
+          //^ &'? E
             x;
-          //^ &E
+          //^ &'? E
         }
     }
 }",
@@ -2040,3 +1961,41 @@
 "#,
     )
 }
+
+#[test]
+fn cfg_first_trait_param_16141() {
+    check_no_mismatches(
+        r#"
+//- minicore: sized, coerce_unsized
+trait Bar {
+    fn bar(&self) {}
+}
+
+impl<#[cfg(feature = "a-feature")] A> Bar for (){}
+"#,
+    )
+}
+
+#[test]
+fn nested_anon_generics_and_where_bounds_17173() {
+    check_types(
+        r#"
+//- minicore: sized, fn
+pub trait Lookup {
+    type Data;
+    fn lookup(&self) -> Self::Data;
+}
+pub trait ItemTreeLoc {
+    type Id;
+}
+fn id_to_generics(id: impl Lookup<Data = impl ItemTreeLoc<Id = ()>>,
+                //^^ impl Lookup<Data = impl ItemTreeLoc<Id = ()>>
+                enabled_params: impl Fn(),
+              //^^^^^^^^^^^^^^  impl Fn()
+                )
+where
+    (): Sized,
+{}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index a9d28eb..e2cd7fa 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -115,15 +115,15 @@
             8..9 'a': u32
             16..17 'b': isize
             26..27 'c': !
-            32..33 'd': &str
+            32..33 'd': &'? str
             41..120 '{     ...f32; }': ()
             47..48 'a': u32
             54..55 'b': isize
             61..62 'c': !
-            68..69 'd': &str
+            68..69 'd': &'? str
             75..81 '1usize': usize
             87..93 '1isize': isize
-            99..105 '"test"': &str
+            99..105 '"test"': &'static str
             111..117 '1.0f32': f32
         "#]],
     );
@@ -344,23 +344,23 @@
 }
         "#,
         expect![[r#"
-            8..9 'a': &u32
-            17..18 'b': &mut u32
+            8..9 'a': &'? u32
+            17..18 'b': &'? mut u32
             30..31 'c': *const u32
             45..46 'd': *mut u32
             58..149 '{     ... *d; }': ()
-            64..65 'a': &u32
+            64..65 'a': &'? u32
             71..73 '*a': u32
-            72..73 'a': &u32
-            79..81 '&a': &&u32
-            80..81 'a': &u32
-            87..93 '&mut a': &mut &u32
-            92..93 'a': &u32
-            99..100 'b': &mut u32
+            72..73 'a': &'? u32
+            79..81 '&a': &'? &'? u32
+            80..81 'a': &'? u32
+            87..93 '&mut a': &'? mut &'? u32
+            92..93 'a': &'? u32
+            99..100 'b': &'? mut u32
             106..108 '*b': u32
-            107..108 'b': &mut u32
-            114..116 '&b': &&mut u32
-            115..116 'b': &mut u32
+            107..108 'b': &'? mut u32
+            114..116 '&b': &'? &'? mut u32
+            115..116 'b': &'? mut u32
             122..123 'c': *const u32
             129..131 '*c': u32
             130..131 'c': *const u32
@@ -425,22 +425,22 @@
             32..36 '5i32': i32
             50..54 '5f32': f32
             68..72 '5f64': f64
-            86..93 '"hello"': &str
-            107..115 'b"bytes"': &[u8; 5]
+            86..93 '"hello"': &'static str
+            107..115 'b"bytes"': &'static [u8; 5]
             129..132 ''c'': char
             146..150 'b'b'': u8
             164..168 '3.14': f64
             182..186 '5000': i32
             200..205 'false': bool
             219..223 'true': bool
-            237..333 'r#"   ...    "#': &str
-            347..357 'br#"yolo"#': &[u8; 4]
-            375..376 'a': &[u8; 4]
-            379..403 'b"a\x2...    c"': &[u8; 4]
-            421..422 'b': &[u8; 4]
-            425..433 'br"g\ h"': &[u8; 4]
-            451..452 'c': &[u8; 6]
-            455..467 'br#"x"\"yb"#': &[u8; 6]
+            237..333 'r#"   ...    "#': &'static str
+            347..357 'br#"yolo"#': &'static [u8; 4]
+            375..376 'a': &'static [u8; 4]
+            379..403 'b"a\x2...    c"': &'static [u8; 4]
+            421..422 'b': &'static [u8; 4]
+            425..433 'br"g\ h"': &'static [u8; 4]
+            451..452 'c': &'static [u8; 6]
+            455..467 'br#"x"\"yb"#': &'static [u8; 6]
         "##]],
     );
 }
@@ -508,9 +508,9 @@
             238..240 '!x': {unknown}
             239..240 'x': SomeType
             246..254 '-"hello"': {unknown}
-            247..254 '"hello"': &str
+            247..254 '"hello"': &'static str
             260..268 '!"hello"': {unknown}
-            261..268 '"hello"': &str
+            261..268 '"hello"': &'static str
         "#]],
     );
 }
@@ -535,7 +535,7 @@
         expect![[r#"
             13..14 'x': u32
             21..23 '{}': ()
-            77..230 '{     ...t &c }': &mut &f64
+            77..230 '{     ...t &c }': &'? mut &'? f64
             87..88 'a': u32
             91..107 'unknow...nction': {unknown}
             91..109 'unknow...tion()': u32
@@ -550,8 +550,8 @@
             193..194 'c': f64
             197..213 'unknow...nction': {unknown}
             197..215 'unknow...tion()': f64
-            221..228 '&mut &c': &mut &f64
-            226..228 '&c': &f64
+            221..228 '&mut &c': &'? mut &'? f64
+            226..228 '&c': &'? f64
             227..228 'c': f64
         "#]],
     );
@@ -579,12 +579,12 @@
 }
 "#,
         expect![[r#"
-            33..37 'self': &S
+            33..37 'self': &'? S
             39..60 '{     ...     }': ()
-            49..53 'self': &S
-            74..78 'self': &S
+            49..53 'self': &'? S
+            74..78 'self': &'? S
             87..108 '{     ...     }': ()
-            97..101 'self': &S
+            97..101 'self': &'? S
             132..152 '{     ...     }': S
             142..146 'S {}': S
             176..199 '{     ...     }': S
@@ -771,35 +771,35 @@
             64..65 'a': A
             71..73 'a1': A
             71..75 'a1.b': B
-            85..87 'a2': &A
-            90..92 '&a': &A
+            85..87 'a2': &'? A
+            90..92 '&a': &'? A
             91..92 'a': A
-            98..100 'a2': &A
+            98..100 'a2': &'? A
             98..102 'a2.b': B
-            112..114 'a3': &mut A
-            117..123 '&mut a': &mut A
+            112..114 'a3': &'? mut A
+            117..123 '&mut a': &'? mut A
             122..123 'a': A
-            129..131 'a3': &mut A
+            129..131 'a3': &'? mut A
             129..133 'a3.b': B
-            143..145 'a4': &&&&&&&A
-            148..156 '&&&&&&&a': &&&&&&&A
-            149..156 '&&&&&&a': &&&&&&A
-            150..156 '&&&&&a': &&&&&A
-            151..156 '&&&&a': &&&&A
-            152..156 '&&&a': &&&A
-            153..156 '&&a': &&A
-            154..156 '&a': &A
+            143..145 'a4': &'? &'? &'? &'? &'? &'? &'? A
+            148..156 '&&&&&&&a': &'? &'? &'? &'? &'? &'? &'? A
+            149..156 '&&&&&&a': &'? &'? &'? &'? &'? &'? A
+            150..156 '&&&&&a': &'? &'? &'? &'? &'? A
+            151..156 '&&&&a': &'? &'? &'? &'? A
+            152..156 '&&&a': &'? &'? &'? A
+            153..156 '&&a': &'? &'? A
+            154..156 '&a': &'? A
             155..156 'a': A
-            162..164 'a4': &&&&&&&A
+            162..164 'a4': &'? &'? &'? &'? &'? &'? &'? A
             162..166 'a4.b': B
-            176..178 'a5': &mut &&mut &&mut A
-            181..199 '&mut &...&mut a': &mut &&mut &&mut A
-            186..199 '&&mut &&mut a': &&mut &&mut A
-            187..199 '&mut &&mut a': &mut &&mut A
-            192..199 '&&mut a': &&mut A
-            193..199 '&mut a': &mut A
+            176..178 'a5': &'? mut &'? &'? mut &'? &'? mut A
+            181..199 '&mut &...&mut a': &'? mut &'? &'? mut &'? &'? mut A
+            186..199 '&&mut &&mut a': &'? &'? mut &'? &'? mut A
+            187..199 '&mut &&mut a': &'? mut &'? &'? mut A
+            192..199 '&&mut a': &'? &'? mut A
+            193..199 '&mut a': &'? mut A
             198..199 'a': A
-            205..207 'a5': &mut &&mut &&mut A
+            205..207 'a5': &'? mut &'? &'? mut &'? &'? mut A
             205..209 'a5.b': B
             223..225 'a1': *const A
             237..239 'a2': *mut A
@@ -840,22 +840,22 @@
 }
 "#,
         expect![[r#"
-            66..70 'self': &A<T>
-            78..101 '{     ...     }': &T
-            88..95 '&self.0': &T
-            89..93 'self': &A<T>
+            66..70 'self': &'? A<T>
+            78..101 '{     ...     }': &'? T
+            88..95 '&self.0': &'? T
+            89..93 'self': &'? A<T>
             89..95 'self.0': T
-            182..186 'self': &B<T>
-            205..228 '{     ...     }': &T
-            215..222 '&self.0': &T
-            216..220 'self': &B<T>
+            182..186 'self': &'? B<T>
+            205..228 '{     ...     }': &'? T
+            215..222 '&self.0': &'? T
+            216..220 'self': &'? B<T>
             216..222 'self.0': T
             242..280 '{     ...))); }': ()
-            252..253 't': &i32
-            256..262 'A::foo': fn foo<i32>(&A<i32>) -> &i32
-            256..277 'A::foo...42))))': &i32
-            263..276 '&&B(B(A(42)))': &&B<B<A<i32>>>
-            264..276 '&B(B(A(42)))': &B<B<A<i32>>>
+            252..253 't': &'? i32
+            256..262 'A::foo': fn foo<i32>(&'? A<i32>) -> &'? i32
+            256..277 'A::foo...42))))': &'? i32
+            263..276 '&&B(B(A(42)))': &'? &'? B<B<A<i32>>>
+            264..276 '&B(B(A(42)))': &'? B<B<A<i32>>>
             265..266 'B': extern "rust-call" B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>>
             265..276 'B(B(A(42)))': B<B<A<i32>>>
             267..268 'B': extern "rust-call" B<A<i32>>(A<i32>) -> B<A<i32>>
@@ -895,28 +895,28 @@
 }
 "#,
         expect![[r#"
-            71..75 'self': &A<T>
-            77..78 'x': &A<T>
-            93..114 '{     ...     }': &T
-            103..108 '&*x.0': &T
+            71..75 'self': &'? A<T>
+            77..78 'x': &'? A<T>
+            93..114 '{     ...     }': &'? T
+            103..108 '&*x.0': &'? T
             104..108 '*x.0': T
-            105..106 'x': &A<T>
+            105..106 'x': &'? A<T>
             105..108 'x.0': *mut T
-            195..199 'self': &B<T>
-            218..241 '{     ...     }': &T
-            228..235 '&self.0': &T
-            229..233 'self': &B<T>
+            195..199 'self': &'? B<T>
+            218..241 '{     ...     }': &'? T
+            228..235 '&self.0': &'? T
+            229..233 'self': &'? B<T>
             229..235 'self.0': T
             253..254 'a': A<i32>
             264..310 '{     ...))); }': ()
-            274..275 't': &i32
+            274..275 't': &'? i32
             278..279 'A': extern "rust-call" A<i32>(*mut i32) -> A<i32>
             278..292 'A(0 as *mut _)': A<i32>
-            278..307 'A(0 as...B(a)))': &i32
+            278..307 'A(0 as...B(a)))': &'? i32
             280..281 '0': i32
             280..291 '0 as *mut _': *mut i32
-            297..306 '&&B(B(a))': &&B<B<A<i32>>>
-            298..306 '&B(B(a))': &B<B<A<i32>>>
+            297..306 '&&B(B(a))': &'? &'? B<B<A<i32>>>
+            298..306 '&B(B(a))': &'? B<B<A<i32>>>
             299..300 'B': extern "rust-call" B<B<A<i32>>>(B<A<i32>>) -> B<B<A<i32>>>
             299..306 'B(B(a))': B<B<A<i32>>>
             301..302 'B': extern "rust-call" B<A<i32>>(A<i32>) -> B<A<i32>>
@@ -1044,7 +1044,7 @@
             31..35 'self': A
             37..38 'x': u32
             52..54 '{}': i32
-            106..110 'self': &A
+            106..110 'self': &'? A
             112..113 'x': u64
             127..129 '{}': i64
             147..148 'a': A
@@ -1053,7 +1053,7 @@
             159..167 'a.foo(1)': i32
             165..166 '1': u32
             173..184 '(&a).bar(1)': i64
-            174..176 '&a': &A
+            174..176 '&a': &'? A
             175..176 'a': A
             182..183 '1': u64
             190..191 'a': A
@@ -1078,10 +1078,10 @@
 }
 "#,
         expect![[r#"
-            67..71 'self': &str
+            67..71 'self': &'? str
             80..82 '{}': i32
             96..116 '{     ...o(); }': ()
-            102..107 '"foo"': &str
+            102..107 '"foo"': &'static str
             102..113 '"foo".foo()': i32
         "#]],
     );
@@ -1101,33 +1101,33 @@
         }
         "#,
         expect![[r#"
-            8..9 'x': &str
+            8..9 'x': &'? str
             17..18 'y': isize
             27..169 '{     ...d"); }': ()
-            37..38 'a': (u32, &str)
-            54..62 '(1, "a")': (u32, &str)
+            37..38 'a': (u32, &'? str)
+            54..62 '(1, "a")': (u32, &'? str)
             55..56 '1': u32
-            58..61 '"a"': &str
-            72..73 'b': ((u32, &str), &str)
-            76..82 '(a, x)': ((u32, &str), &str)
-            77..78 'a': (u32, &str)
-            80..81 'x': &str
-            92..93 'c': (isize, &str)
-            96..102 '(y, x)': (isize, &str)
+            58..61 '"a"': &'static str
+            72..73 'b': ((u32, &'? str), &'? str)
+            76..82 '(a, x)': ((u32, &'? str), &'? str)
+            77..78 'a': (u32, &'? str)
+            80..81 'x': &'? str
+            92..93 'c': (isize, &'? str)
+            96..102 '(y, x)': (isize, &'? str)
             97..98 'y': isize
-            100..101 'x': &str
-            112..113 'd': ((isize, &str), &str)
-            116..122 '(c, x)': ((isize, &str), &str)
-            117..118 'c': (isize, &str)
-            120..121 'x': &str
-            132..133 'e': (i32, &str)
-            136..144 '(1, "e")': (i32, &str)
+            100..101 'x': &'? str
+            112..113 'd': ((isize, &'? str), &'? str)
+            116..122 '(c, x)': ((isize, &'? str), &'? str)
+            117..118 'c': (isize, &'? str)
+            120..121 'x': &'? str
+            132..133 'e': (i32, &'static str)
+            136..144 '(1, "e")': (i32, &'static str)
             137..138 '1': i32
-            140..143 '"e"': &str
-            154..155 'f': ((i32, &str), &str)
-            158..166 '(e, "d")': ((i32, &str), &str)
-            159..160 'e': (i32, &str)
-            162..165 '"d"': &str
+            140..143 '"e"': &'static str
+            154..155 'f': ((i32, &'static str), &'static str)
+            158..166 '(e, "d")': ((i32, &'static str), &'static str)
+            159..160 'e': (i32, &'static str)
+            162..165 '"d"': &'static str
         "#]],
     );
 }
@@ -1156,20 +1156,20 @@
         }
         "#,
         expect![[r#"
-            8..9 'x': &str
+            8..9 'x': &'? str
             17..18 'y': isize
             27..326 '{     ...,4]; }': ()
-            37..38 'a': [&str; 1]
-            41..44 '[x]': [&str; 1]
-            42..43 'x': &str
-            54..55 'b': [[&str; 1]; 2]
-            58..64 '[a, a]': [[&str; 1]; 2]
-            59..60 'a': [&str; 1]
-            62..63 'a': [&str; 1]
-            74..75 'c': [[[&str; 1]; 2]; 2]
-            78..84 '[b, b]': [[[&str; 1]; 2]; 2]
-            79..80 'b': [[&str; 1]; 2]
-            82..83 'b': [[&str; 1]; 2]
+            37..38 'a': [&'? str; 1]
+            41..44 '[x]': [&'? str; 1]
+            42..43 'x': &'? str
+            54..55 'b': [[&'? str; 1]; 2]
+            58..64 '[a, a]': [[&'? str; 1]; 2]
+            59..60 'a': [&'? str; 1]
+            62..63 'a': [&'? str; 1]
+            74..75 'c': [[[&'? str; 1]; 2]; 2]
+            78..84 '[b, b]': [[[&'? str; 1]; 2]; 2]
+            79..80 'b': [[&'? str; 1]; 2]
+            82..83 'b': [[&'? str; 1]; 2]
             95..96 'd': [isize; 4]
             99..111 '[y, 1, 2, 3]': [isize; 4]
             100..101 'y': isize
@@ -1197,15 +1197,15 @@
             209..215 '[1, 2]': [i32; 2]
             210..211 '1': i32
             213..214 '2': i32
-            225..226 'i': [&str; 2]
-            229..239 '["a", "b"]': [&str; 2]
-            230..233 '"a"': &str
-            235..238 '"b"': &str
-            250..251 'b': [[&str; 1]; 2]
-            254..264 '[a, ["b"]]': [[&str; 1]; 2]
-            255..256 'a': [&str; 1]
-            258..263 '["b"]': [&str; 1]
-            259..262 '"b"': &str
+            225..226 'i': [&'? str; 2]
+            229..239 '["a", "b"]': [&'? str; 2]
+            230..233 '"a"': &'static str
+            235..238 '"b"': &'static str
+            250..251 'b': [[&'? str; 1]; 2]
+            254..264 '[a, ["b"]]': [[&'? str; 1]; 2]
+            255..256 'a': [&'? str; 1]
+            258..263 '["b"]': [&'? str; 1]
+            259..262 '"b"': &'static str
             274..275 'x': [u8; 0]
             287..289 '[]': [u8; 0]
             299..300 'y': [u8; 4]
@@ -1279,12 +1279,12 @@
             92..93 'A': extern "rust-call" A<u128>(u128) -> A<u128>
             92..101 'A(42u128)': A<u128>
             94..100 '42u128': u128
-            107..111 'Some': extern "rust-call" Some<&str>(&str) -> Option<&str>
-            107..116 'Some("x")': Option<&str>
-            112..115 '"x"': &str
-            122..134 'Option::Some': extern "rust-call" Some<&str>(&str) -> Option<&str>
-            122..139 'Option...e("x")': Option<&str>
-            135..138 '"x"': &str
+            107..111 'Some': extern "rust-call" Some<&'static str>(&'static str) -> Option<&'static str>
+            107..116 'Some("x")': Option<&'static str>
+            112..115 '"x"': &'static str
+            122..134 'Option::Some': extern "rust-call" Some<&'static str>(&'static str) -> Option<&'static str>
+            122..139 'Option...e("x")': Option<&'static str>
+            135..138 '"x"': &'static str
             145..149 'None': Option<{unknown}>
             159..160 'x': Option<i64>
             176..180 'None': Option<i64>
@@ -1405,15 +1405,15 @@
         }
         "#,
         expect![[r#"
-            77..81 'self': &Option<T>
-            97..99 '{}': Option<&T>
+            77..81 'self': &'? Option<T>
+            97..99 '{}': Option<&'? T>
             110..111 'o': Option<u32>
             126..164 '{     ...f(); }': ()
-            132..145 '(&o).as_ref()': Option<&u32>
-            133..135 '&o': &Option<u32>
+            132..145 '(&o).as_ref()': Option<&'? u32>
+            133..135 '&o': &'? Option<u32>
             134..135 'o': Option<u32>
             151..152 'o': Option<u32>
-            151..161 'o.as_ref()': Option<&u32>
+            151..161 'o.as_ref()': Option<&'? u32>
         "#]],
     );
 }
@@ -1551,16 +1551,16 @@
         "#,
         expect![[r#"
             115..116 'x': A<u32, i128>
-            123..124 'y': A<&str, u128>
+            123..124 'y': A<&'? str, u128>
             137..138 'z': A<u8, i8>
             153..210 '{     ...z.y; }': ()
             159..160 'x': A<u32, i128>
             159..162 'x.x': u32
             168..169 'x': A<u32, i128>
             168..171 'x.y': i128
-            177..178 'y': A<&str, u128>
-            177..180 'y.x': &str
-            186..187 'y': A<&str, u128>
+            177..178 'y': A<&'? str, u128>
+            177..180 'y.x': &'? str
+            186..187 'y': A<&'? str, u128>
             186..189 'y.y': u128
             195..196 'z': A<u8, i8>
             195..198 'z.x': u8
@@ -1572,8 +1572,8 @@
             312..328 'm::Ali...Foo(0)': Enum
             326..327 '0': u8
             338..354 'm::Ali...Foo(x)': Enum
-            352..353 'x': &u8
-            357..359 '&e': &Enum
+            352..353 'x': &'? u8
+            357..359 '&e': &'? Enum
             358..359 'e': Enum
         "#]],
     )
@@ -1618,10 +1618,10 @@
             9..10 'x': T
             20..29 '{     x }': T
             26..27 'x': T
-            43..44 'x': &T
+            43..44 'x': &'? T
             55..65 '{     *x }': T
             61..63 '*x': T
-            62..63 'x': &T
+            62..63 'x': &'? T
             77..157 '{     ...(1); }': ()
             87..88 'y': u32
             91..96 '10u32': u32
@@ -1629,9 +1629,9 @@
             102..107 'id(y)': u32
             105..106 'y': u32
             117..118 'x': bool
-            127..132 'clone': fn clone<bool>(&bool) -> bool
+            127..132 'clone': fn clone<bool>(&'? bool) -> bool
             127..135 'clone(z)': bool
-            133..134 'z': &bool
+            133..134 'z': &'? bool
             141..151 'id::<i128>': fn id<i128>(i128) -> i128
             141..154 'id::<i128>(1)': i128
             152..153 '1': i128
@@ -1842,7 +1842,7 @@
 
 fn main() {
     foo();
-  //^^^^^ &str
+  //^^^^^ &'static str
 }"#,
     );
 }
@@ -1940,10 +1940,10 @@
         "#,
         expect![[r#"
             16..46 '{     ..." }; }': u32
-            26..27 'x': impl Fn() -> &str
-            30..43 '|| { "test" }': impl Fn() -> &str
-            33..43 '{ "test" }': &str
-            35..41 '"test"': &str
+            26..27 'x': impl Fn() -> &'static str
+            30..43 '|| { "test" }': impl Fn() -> &'static str
+            33..43 '{ "test" }': &'static str
+            35..41 '"test"': &'static str
         "#]],
     );
 }
@@ -1975,10 +1975,10 @@
             70..71 'v': i64
             78..80 '{}': ()
             91..362 '{     ...   } }': ()
-            101..106 'mut g': |usize| yields i64 -> &str
-            109..218 '|r| { ...     }': |usize| yields i64 -> &str
+            101..106 'mut g': |usize| yields i64 -> &'static str
+            109..218 '|r| { ...     }': |usize| yields i64 -> &'static str
             110..111 'r': usize
-            113..218 '{     ...     }': &str
+            113..218 '{     ...     }': &'static str
             127..128 'a': usize
             131..138 'yield 0': usize
             137..138 '0': i64
@@ -1988,22 +1988,22 @@
             177..178 'a': usize
             181..188 'yield 2': usize
             187..188 '2': i64
-            198..212 '"return value"': &str
+            198..212 '"return value"': &'static str
             225..360 'match ...     }': ()
-            231..239 'Pin::new': fn new<&mut |usize| yields i64 -> &str>(&mut |usize| yields i64 -> &str) -> Pin<&mut |usize| yields i64 -> &str>
-            231..247 'Pin::n...mut g)': Pin<&mut |usize| yields i64 -> &str>
-            231..262 'Pin::n...usize)': CoroutineState<i64, &str>
-            240..246 '&mut g': &mut |usize| yields i64 -> &str
-            245..246 'g': |usize| yields i64 -> &str
+            231..239 'Pin::new': fn new<&'? mut |usize| yields i64 -> &'static str>(&'? mut |usize| yields i64 -> &'static str) -> Pin<&'? mut |usize| yields i64 -> &'static str>
+            231..247 'Pin::n...mut g)': Pin<&'? mut |usize| yields i64 -> &'static str>
+            231..262 'Pin::n...usize)': CoroutineState<i64, &'static str>
+            240..246 '&mut g': &'? mut |usize| yields i64 -> &'static str
+            245..246 'g': |usize| yields i64 -> &'static str
             255..261 '0usize': usize
-            273..299 'Corout...ded(y)': CoroutineState<i64, &str>
+            273..299 'Corout...ded(y)': CoroutineState<i64, &'static str>
             297..298 'y': i64
             303..312 '{ f(y); }': ()
             305..306 'f': fn f(i64)
             305..309 'f(y)': ()
             307..308 'y': i64
-            321..348 'Corout...ete(r)': CoroutineState<i64, &str>
-            346..347 'r': &str
+            321..348 'Corout...ete(r)': CoroutineState<i64, &'static str>
+            346..347 'r': &'static str
             352..354 '{}': ()
         "#]],
     );
@@ -2050,7 +2050,7 @@
         _ => loop {},
     };
     f;
-  //^ (&&&&i32, &&&i32)
+  //^ (&'? &'? &'? &'? i32, &'? &'? &'? i32)
 }
         "#,
     );
@@ -2059,10 +2059,10 @@
 fn f() {
     let x = &&&(&&&2, &&&&&3);
     let (y, z) = x;
-       //^ &&&&i32
+       //^ &'? &'? &'? &'? i32
     let t @ (y, z) = x;
     t;
-  //^ &&&(&&&i32, &&&&&i32)
+  //^ &'? &'? &'? (&'? &'? &'? i32, &'? &'? &'? &'? &'? i32)
 }
         "#,
     );
@@ -2071,10 +2071,10 @@
 fn f() {
     let x = &&&(&&&2, &&&&&3);
     let (y, z) = x;
-       //^ &&&&i32
+       //^ &'? &'? &'? &'? i32
     let t @ (y, z) = x;
     t;
-  //^ &&&(&&&i32, &&&&&i32)
+  //^ &'? &'? &'? (&'? &'? &'? i32, &'? &'? &'? &'? &'? i32)
 }
         "#,
     );
@@ -2761,23 +2761,23 @@
 fn f() {
     let x = S;
     let c1 = || x.read();
-      //^^ impl Fn() -> &S
+      //^^ impl Fn() -> &'? S
     let c2 = || x.write();
-      //^^ impl FnMut() -> &mut S
+      //^^ impl FnMut() -> &'? mut S
     let c3 = || x.consume();
       //^^ impl FnOnce() -> S
     let c3 = || x.consume().consume().consume();
       //^^ impl FnOnce() -> S
     let c3 = || x.consume().write().read();
-      //^^ impl FnOnce() -> &S
+      //^^ impl FnOnce() -> &'? S
     let x = &mut x;
     let c1 = || x.write();
-      //^^ impl FnMut() -> &mut S
+      //^^ impl FnMut() -> &'? mut S
     let x = S;
     let c1 = || { let ref t = x; t };
-      //^^ impl Fn() -> &S
+      //^^ impl Fn() -> &'? S
     let c2 = || { let ref mut t = x; t };
-      //^^ impl FnMut() -> &mut S
+      //^^ impl FnMut() -> &'? mut S
     let c3 = || { let t = x; t };
       //^^ impl FnOnce() -> S
 }
@@ -3074,11 +3074,11 @@
 }
         "#,
         expect![[r#"
-            104..108 'self': &Box<T>
-            188..192 'self': &Box<Foo<T>>
-            218..220 '{}': &T
-            242..246 'self': &Box<Foo<T>>
-            275..277 '{}': &Foo<T>
+            104..108 'self': &'? Box<T>
+            188..192 'self': &'a Box<Foo<T>>
+            218..220 '{}': &'a T
+            242..246 'self': &'a Box<Foo<T>>
+            275..277 '{}': &'a Foo<T>
             297..301 'self': Box<Foo<T>>
             322..324 '{}': Foo<T>
             338..559 '{     ...r(); }': ()
@@ -3088,21 +3088,21 @@
             360..363 'Foo': extern "rust-call" Foo<i32>(i32) -> Foo<i32>
             360..370 'Foo(0_i32)': Foo<i32>
             364..369 '0_i32': i32
-            382..386 'bad1': &i32
+            382..386 'bad1': &'? i32
             389..394 'boxed': Box<Foo<i32>>
-            389..406 'boxed....nner()': &i32
-            416..421 'good1': &i32
-            424..438 'Foo::get_inner': fn get_inner<i32, '{error}>(&Box<Foo<i32>>) -> &i32
-            424..446 'Foo::g...boxed)': &i32
-            439..445 '&boxed': &Box<Foo<i32>>
+            389..406 'boxed....nner()': &'? i32
+            416..421 'good1': &'? i32
+            424..438 'Foo::get_inner': fn get_inner<i32, '?>(&'? Box<Foo<i32>>) -> &'? i32
+            424..446 'Foo::g...boxed)': &'? i32
+            439..445 '&boxed': &'? Box<Foo<i32>>
             440..445 'boxed': Box<Foo<i32>>
-            457..461 'bad2': &Foo<i32>
+            457..461 'bad2': &'? Foo<i32>
             464..469 'boxed': Box<Foo<i32>>
-            464..480 'boxed....self()': &Foo<i32>
-            490..495 'good2': &Foo<i32>
-            498..511 'Foo::get_self': fn get_self<i32, '{error}>(&Box<Foo<i32>>) -> &Foo<i32>
-            498..519 'Foo::g...boxed)': &Foo<i32>
-            512..518 '&boxed': &Box<Foo<i32>>
+            464..480 'boxed....self()': &'? Foo<i32>
+            490..495 'good2': &'? Foo<i32>
+            498..511 'Foo::get_self': fn get_self<i32, '?>(&'? Box<Foo<i32>>) -> &'? Foo<i32>
+            498..519 'Foo::g...boxed)': &'? Foo<i32>
+            512..518 '&boxed': &'? Box<Foo<i32>>
             513..518 'boxed': Box<Foo<i32>>
             530..535 'inner': Foo<i32>
             538..543 'boxed': Box<Foo<i32>>
@@ -3414,31 +3414,31 @@
 fn main() {
     let x;
     [x,] = &[1,];
-  //^^^^expected &[i32; 1], got [{unknown}; _]
+  //^^^^expected &'? [i32; 1], got [{unknown}; _]
 
     let x;
     [(x,),] = &[(1,),];
-  //^^^^^^^expected &[(i32,); 1], got [{unknown}; _]
+  //^^^^^^^expected &'? [(i32,); 1], got [{unknown}; _]
 
     let x;
     ((x,),) = &((1,),);
-  //^^^^^^^expected &((i32,),), got (({unknown},),)
+  //^^^^^^^expected &'? ((i32,),), got (({unknown},),)
 
     let x;
     (x,) = &(1,);
-  //^^^^expected &(i32,), got ({unknown},)
+  //^^^^expected &'? (i32,), got ({unknown},)
 
     let x;
     (S { a: x },) = &(S { a: 42 },);
-  //^^^^^^^^^^^^^expected &(S,), got (S,)
+  //^^^^^^^^^^^^^expected &'? (S,), got (S,)
 
     let x;
     S { a: x } = &S { a: 42 };
-  //^^^^^^^^^^expected &S, got S
+  //^^^^^^^^^^expected &'? S, got S
 
     let x;
     TS(x) = &TS(42);
-  //^^^^^expected &TS, got TS
+  //^^^^^expected &'? TS, got TS
 }
         "#,
     );
@@ -3548,17 +3548,17 @@
 }
 "#,
         expect![[r#"
-            47..51 'self': &Ark<T>
+            47..51 'self': &'? Ark<T>
             65..88 '{     ...     }': *const T
-            75..82 '&self.0': &T
-            76..80 'self': &Ark<T>
+            75..82 '&self.0': &'? T
+            76..80 'self': &'? Ark<T>
             76..82 'self.0': T
             99..100 't': Ark<T>
             110..144 '{     ... (); }': ()
-            116..124 'Ark::foo': fn foo<T>(&Ark<T>) -> *const T
+            116..124 'Ark::foo': fn foo<T>(&'? Ark<T>) -> *const T
             116..128 'Ark::foo(&t)': *const T
             116..141 'Ark::f...nst ()': *const ()
-            125..127 '&t': &Ark<T>
+            125..127 '&t': &'? Ark<T>
             126..127 't': Ark<T>
         "#]],
     );
@@ -3632,7 +3632,7 @@
 
 fn main() {
     c"ello";
-  //^^^^^^^ &CStr
+  //^^^^^^^ &'static CStr
 }
 "#,
     );
@@ -3659,7 +3659,25 @@
     let are = "are";
     let count = 10;
     builtin#format_args("hello {count:02} {} friends, we {are:?} {0}{last}", "fancy", last = "!");
- // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'{error}>
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type: Arguments<'?>
+}
+"#,
+    );
+}
+
+#[test]
+fn inline_const_expression() {
+    check(
+        r#"
+fn main() {
+    let foo = 0;
+    const {
+        let bar = 1;
+        let unresolved = foo;
+         // ^^^^^^^^^^ type: {unknown}
+        let resolved = bar;
+         // ^^^^^^^^ type: i32
+    }
 }
 "#,
     );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index dfcd322a..18fc8af 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -238,6 +238,7 @@
 //- minicore: iterator
 //- /main.rs crate:main deps:alloc
 #![no_std]
+extern crate alloc;
 use alloc::collections::Vec;
 
 fn test() {
@@ -245,7 +246,7 @@
     v.push("foo");
     for x in v {
         x;
-    } //^ &str
+    } //^ &'static str
 }
 
 //- /alloc.rs crate:alloc
@@ -575,7 +576,7 @@
         "fn main() { &mut [9][2]; }",
         expect![[r#"
             10..26 '{ &mut...[2]; }': ()
-            12..23 '&mut [9][2]': &mut {unknown}
+            12..23 '&mut [9][2]': &'? mut {unknown}
             17..20 '[9]': [i32; 1]
             17..23 '[9][2]': {unknown}
             18..19 '9': i32
@@ -873,7 +874,7 @@
 
 fn test(o: O<S>) {
     o.foo();
-} //^^^^^^^ &str
+} //^^^^^^^ &'? str
 "#,
     );
 }
@@ -1016,15 +1017,15 @@
     z.foo2();
 }"#,
         expect![[r#"
-            29..33 'self': &Self
-            54..58 'self': &Self
+            29..33 'self': &'? Self
+            54..58 'self': &'? Self
             77..78 'x': impl Trait<u16>
             97..99 '{}': ()
             154..155 'x': impl Trait<u64>
-            174..175 'y': &impl Trait<u32>
+            174..175 'y': &'? impl Trait<u32>
             195..323 '{     ...2(); }': ()
             201..202 'x': impl Trait<u64>
-            208..209 'y': &impl Trait<u32>
+            208..209 'y': &'? impl Trait<u32>
             219..220 'z': S<u16>
             223..224 'S': extern "rust-call" S<u16>(u16) -> S<u16>
             223..227 'S(1)': S<u16>
@@ -1034,13 +1035,13 @@
             237..238 'z': S<u16>
             245..246 'x': impl Trait<u64>
             245..252 'x.foo()': u64
-            258..259 'y': &impl Trait<u32>
+            258..259 'y': &'? impl Trait<u32>
             258..265 'y.foo()': u32
             271..272 'z': S<u16>
             271..278 'z.foo()': u16
             284..285 'x': impl Trait<u64>
             284..292 'x.foo2()': i64
-            298..299 'y': &impl Trait<u32>
+            298..299 'y': &'? impl Trait<u32>
             298..306 'y.foo2()': i64
             312..313 'z': S<u16>
             312..320 'z.foo2()': i64
@@ -1204,26 +1205,26 @@
     z.foo2();
 }"#,
         expect![[r#"
-            29..33 'self': &Self
-            54..58 'self': &Self
+            29..33 'self': &'? Self
+            54..58 'self': &'? Self
             98..100 '{}': ()
             110..111 'x': impl Trait<u64>
-            130..131 'y': &impl Trait<u64>
+            130..131 'y': &'? impl Trait<u64>
             151..268 '{     ...2(); }': ()
             157..158 'x': impl Trait<u64>
-            164..165 'y': &impl Trait<u64>
+            164..165 'y': &'? impl Trait<u64>
             175..176 'z': impl Trait<u64>
             179..182 'bar': fn bar() -> impl Trait<u64>
             179..184 'bar()': impl Trait<u64>
             190..191 'x': impl Trait<u64>
             190..197 'x.foo()': u64
-            203..204 'y': &impl Trait<u64>
+            203..204 'y': &'? impl Trait<u64>
             203..210 'y.foo()': u64
             216..217 'z': impl Trait<u64>
             216..223 'z.foo()': u64
             229..230 'x': impl Trait<u64>
             229..237 'x.foo2()': i64
-            243..244 'y': &impl Trait<u64>
+            243..244 'y': &'? impl Trait<u64>
             243..251 'y.foo2()': i64
             257..258 'z': impl Trait<u64>
             257..265 'z.foo2()': i64
@@ -1328,7 +1329,7 @@
     a.foo();
 }"#,
         expect![[r#"
-            29..33 'self': &Self
+            29..33 'self': &'? Self
             71..82 '{ loop {} }': !
             73..80 'loop {}': !
             78..80 '{}': ()
@@ -1366,8 +1367,8 @@
     d.foo();
 }"#,
         expect![[r#"
-            49..53 'self': &mut Self
-            101..105 'self': &Self
+            49..53 'self': &'? mut Self
+            101..105 'self': &'? Self
             184..195 '{ loop {} }': ({unknown}, {unknown})
             186..193 'loop {}': !
             191..193 '{}': ()
@@ -1414,10 +1415,10 @@
 }
 "#,
         expect![[r#"
-            134..165 '{     ...(C)) }': (impl FnOnce(&str, T), Bar<u8>)
-            140..163 '(|inpu...ar(C))': (impl FnOnce(&str, T), Bar<u8>)
-            141..154 '|input, t| {}': impl FnOnce(&str, T)
-            142..147 'input': &str
+            134..165 '{     ...(C)) }': (impl FnOnce(&'? str, T), Bar<u8>)
+            140..163 '(|inpu...ar(C))': (impl FnOnce(&'? str, T), Bar<u8>)
+            141..154 '|input, t| {}': impl FnOnce(&'? str, T)
+            142..147 'input': &'? str
             149..150 't': T
             152..154 '{}': ()
             156..159 'Bar': extern "rust-call" Bar<u8>(u8) -> Bar<u8>
@@ -1466,26 +1467,26 @@
     z.foo2();
 }"#,
         expect![[r#"
-            29..33 'self': &Self
-            54..58 'self': &Self
+            29..33 'self': &'? Self
+            54..58 'self': &'? Self
             97..99 '{}': dyn Trait<u64>
             109..110 'x': dyn Trait<u64>
-            128..129 'y': &dyn Trait<u64>
+            128..129 'y': &'? dyn Trait<u64>
             148..265 '{     ...2(); }': ()
             154..155 'x': dyn Trait<u64>
-            161..162 'y': &dyn Trait<u64>
+            161..162 'y': &'? dyn Trait<u64>
             172..173 'z': dyn Trait<u64>
             176..179 'bar': fn bar() -> dyn Trait<u64>
             176..181 'bar()': dyn Trait<u64>
             187..188 'x': dyn Trait<u64>
             187..194 'x.foo()': u64
-            200..201 'y': &dyn Trait<u64>
+            200..201 'y': &'? dyn Trait<u64>
             200..207 'y.foo()': u64
             213..214 'z': dyn Trait<u64>
             213..220 'z.foo()': u64
             226..227 'x': dyn Trait<u64>
             226..234 'x.foo2()': i64
-            240..241 'y': &dyn Trait<u64>
+            240..241 'y': &'? dyn Trait<u64>
             240..248 'y.foo2()': i64
             254..255 'z': dyn Trait<u64>
             254..262 'z.foo2()': i64
@@ -1514,16 +1515,16 @@
     s.bar().baz();
 }"#,
         expect![[r#"
-            32..36 'self': &Self
-            102..106 'self': &S<T, U>
-            128..139 '{ loop {} }': &dyn Trait<T, U>
+            32..36 'self': &'? Self
+            102..106 'self': &'? S<T, U>
+            128..139 '{ loop {} }': &'? dyn Trait<T, U>
             130..137 'loop {}': !
             135..137 '{}': ()
-            175..179 'self': &Self
+            175..179 'self': &'? Self
             251..252 's': S<u32, i32>
             267..289 '{     ...z(); }': ()
             273..274 's': S<u32, i32>
-            273..280 's.bar()': &dyn Trait<u32, i32>
+            273..280 's.bar()': &'? dyn Trait<u32, i32>
             273..286 's.bar().baz()': (u32, i32)
         "#]],
     );
@@ -1548,19 +1549,19 @@
     z.foo();
 }"#,
         expect![[r#"
-            26..30 'self': &Self
+            26..30 'self': &'? Self
             60..62 '{}': dyn Trait
             72..73 'x': dyn Trait
-            82..83 'y': &dyn Trait
+            82..83 'y': &'? dyn Trait
             100..175 '{     ...o(); }': u64
             106..107 'x': dyn Trait
-            113..114 'y': &dyn Trait
+            113..114 'y': &'? dyn Trait
             124..125 'z': dyn Trait
             128..131 'bar': fn bar() -> dyn Trait
             128..133 'bar()': dyn Trait
             139..140 'x': dyn Trait
             139..146 'x.foo()': u64
-            152..153 'y': &dyn Trait
+            152..153 'y': &'? dyn Trait
             152..159 'y.foo()': u64
             165..166 'z': dyn Trait
             165..172 'z.foo()': u64
@@ -1580,14 +1581,14 @@
 }
         "#,
         expect![[r#"
-            31..35 'self': &S
+            31..35 'self': &'? S
             37..39 '{}': ()
-            47..48 '_': &dyn Fn(S)
+            47..48 '_': &'? dyn Fn(S)
             58..60 '{}': ()
             71..105 '{     ...()); }': ()
-            77..78 'f': fn f(&dyn Fn(S))
+            77..78 'f': fn f(&'? dyn Fn(S))
             77..102 'f(&|nu...foo())': ()
-            79..101 '&|numb....foo()': &impl Fn(S)
+            79..101 '&|numb....foo()': &'? impl Fn(S)
             80..101 '|numbe....foo()': impl Fn(S)
             81..87 'number': S
             89..95 'number': S
@@ -1790,7 +1791,7 @@
     y.foo();
 }"#,
         expect![[r#"
-            53..57 'self': &Self
+            53..57 'self': &'? Self
             66..68 '{}': u32
             185..186 'x': T
             191..192 'y': U
@@ -1819,11 +1820,11 @@
     x.foo();
 }"#,
         expect![[r#"
-            53..57 'self': &Self
+            53..57 'self': &'? Self
             66..68 '{}': u32
-            119..120 'x': &impl Trait1
+            119..120 'x': &'? impl Trait1
             136..152 '{     ...o(); }': ()
-            142..143 'x': &impl Trait1
+            142..143 'x': &'? impl Trait1
             142..149 'x.foo()': u32
         "#]],
     );
@@ -1934,8 +1935,8 @@
     opt.map(f);
 }"#,
         expect![[r#"
-            28..32 'self': &Self
-            132..136 'self': &Bar<F>
+            28..32 'self': &'? Self
+            132..136 'self': &'? Bar<F>
             149..160 '{ loop {} }': (A1, R)
             151..158 'loop {}': !
             156..158 '{}': ()
@@ -1988,7 +1989,7 @@
     let r2 = lazy2.foo();
 }"#,
         expect![[r#"
-            36..40 'self': &Foo
+            36..40 'self': &'? Foo
             51..53 '{}': usize
             131..132 'f': F
             151..153 '{}': Lazy<T, F>
@@ -2262,14 +2263,14 @@
     fn f(&self, x: <Self>::Item) { let y = x; }
 }"#,
         expect![[r#"
-            40..44 'self': &Self
+            40..44 'self': &'? Self
             46..47 'x': Trait::Item<Self>
-            126..130 'self': &S
+            126..130 'self': &'? S
             132..133 'x': u32
             147..161 '{ let y = x; }': ()
             153..154 'y': u32
             157..158 'x': u32
-            228..232 'self': &S2
+            228..232 'self': &'? S2
             234..235 'x': i32
             251..265 '{ let y = x; }': ()
             257..258 'y': i32
@@ -2643,12 +2644,12 @@
             72..74 '_v': F
             117..120 '{ }': ()
             132..163 '{     ... }); }': ()
-            138..148 'f::<(), _>': fn f<(), impl FnOnce(&())>(impl FnOnce(&()))
+            138..148 'f::<(), _>': fn f<(), impl FnOnce(&'? ())>(impl FnOnce(&'? ()))
             138..160 'f::<()... z; })': ()
-            149..159 '|z| { z; }': impl FnOnce(&())
-            150..151 'z': &()
+            149..159 '|z| { z; }': impl FnOnce(&'? ())
+            150..151 'z': &'? ()
             153..159 '{ z; }': ()
-            155..156 'z': &()
+            155..156 'z': &'? ()
         "#]],
     );
 }
@@ -2897,13 +2898,13 @@
     foo(x);
 }"#,
         expect![[r#"
-            21..22 'x': &dyn Foo
+            21..22 'x': &'? dyn Foo
             34..36 '{}': ()
-            46..47 'x': &dyn Foo
+            46..47 'x': &'? dyn Foo
             59..74 '{     foo(x); }': ()
-            65..68 'foo': fn foo(&dyn Foo)
+            65..68 'foo': fn foo(&'? dyn Foo)
             65..71 'foo(x)': ()
-            69..70 'x': &dyn Foo
+            69..70 'x': &'? dyn Foo
         "#]],
     );
 }
@@ -2927,7 +2928,7 @@
     (IsCopy, NotCopy).test();
 }"#,
         expect![[r#"
-            78..82 'self': &Self
+            78..82 'self': &'? Self
             134..235 '{     ...t(); }': ()
             140..146 'IsCopy': IsCopy
             140..153 'IsCopy.test()': bool
@@ -2969,7 +2970,7 @@
             28..29 'T': {unknown}
             36..38 '{}': T
             36..38: expected T, got ()
-            113..117 'self': &Self
+            113..117 'self': &'? Self
             169..249 '{     ...t(); }': ()
             175..178 'foo': fn foo()
             175..185 'foo.test()': bool
@@ -2997,16 +2998,16 @@
     f3.test();
 }"#,
         expect![[r#"
-            22..26 'self': &Self
+            22..26 'self': &'? Self
             76..78 'f1': fn()
             86..88 'f2': fn(usize) -> u8
-            107..109 'f3': fn(u8, u8) -> &u8
+            107..109 'f3': fn(u8, u8) -> &'? u8
             130..178 '{     ...t(); }': ()
             136..138 'f1': fn()
             136..145 'f1.test()': bool
             151..153 'f2': fn(usize) -> u8
             151..160 'f2.test()': bool
-            166..168 'f3': fn(u8, u8) -> &u8
+            166..168 'f3': fn(u8, u8) -> &'? u8
             166..175 'f3.test()': bool
         "#]],
     );
@@ -3027,13 +3028,13 @@
     (1u8, *"foo").test(); // not Sized
 }"#,
         expect![[r#"
-            22..26 'self': &Self
+            22..26 'self': &'? Self
             79..194 '{     ...ized }': ()
             85..88 '1u8': u8
             85..95 '1u8.test()': bool
             101..116 '(*"foo").test()': {unknown}
             102..108 '*"foo"': str
-            103..108 '"foo"': &str
+            103..108 '"foo"': &'static str
             135..145 '(1u8, 1u8)': (u8, u8)
             135..152 '(1u8, ...test()': bool
             136..139 '1u8': u8
@@ -3042,7 +3043,7 @@
             158..178 '(1u8, ...test()': {unknown}
             159..162 '1u8': u8
             164..170 '*"foo"': str
-            165..170 '"foo"': &str
+            165..170 '"foo"': &'static str
         "#]],
     );
 }
@@ -3093,7 +3094,7 @@
             93..94 'x': Option<i32>
             109..111 '{}': ()
             117..124 '(&f)(s)': ()
-            118..120 '&f': &impl Fn(Option<i32>)
+            118..120 '&f': &'? impl Fn(Option<i32>)
             119..120 'f': impl Fn(Option<i32>)
             122..123 's': Option<i32>
         "#]],
@@ -3170,25 +3171,25 @@
     f(&s);
 }"#,
         expect![[r#"
-            154..158 'self': &Box<T>
-            166..205 '{     ...     }': &T
-            176..199 'unsafe...nner }': &T
-            185..197 '&*self.inner': &T
+            154..158 'self': &'? Box<T>
+            166..205 '{     ...     }': &'? T
+            176..199 'unsafe...nner }': &'? T
+            185..197 '&*self.inner': &'? T
             186..197 '*self.inner': T
-            187..191 'self': &Box<T>
+            187..191 'self': &'? Box<T>
             187..197 'self.inner': *mut T
             218..324 '{     ...&s); }': ()
             228..229 's': Option<i32>
             232..236 'None': Option<i32>
-            246..247 'f': Box<dyn FnOnce(&Option<i32>)>
-            281..310 'Box { ... {}) }': Box<dyn FnOnce(&Option<i32>)>
-            294..308 '&mut (|ps| {})': &mut impl FnOnce(&Option<i32>)
-            300..307 '|ps| {}': impl FnOnce(&Option<i32>)
-            301..303 'ps': &Option<i32>
+            246..247 'f': Box<dyn FnOnce(&'? Option<i32>)>
+            281..310 'Box { ... {}) }': Box<dyn FnOnce(&'? Option<i32>)>
+            294..308 '&mut (|ps| {})': &'? mut impl FnOnce(&'? Option<i32>)
+            300..307 '|ps| {}': impl FnOnce(&'? Option<i32>)
+            301..303 'ps': &'? Option<i32>
             305..307 '{}': ()
-            316..317 'f': Box<dyn FnOnce(&Option<i32>)>
+            316..317 'f': Box<dyn FnOnce(&'? Option<i32>)>
             316..321 'f(&s)': ()
-            318..320 '&s': &Option<i32>
+            318..320 '&s': &'? Option<i32>
             319..320 's': Option<i32>
         "#]],
     );
@@ -3320,7 +3321,7 @@
     }
 }"#,
         expect![[r#"
-            46..50 'self': &Self
+            46..50 'self': &'? Self
             58..63 '{ 0 }': u8
             60..61 '0': u8
             115..185 '{     ...   } }': ()
@@ -3595,7 +3596,7 @@
 fn minimized() {
     let v = V::default();
     let p = v.get(&0);
-      //^ &u32
+      //^ &'? u32
     take_u32(42 + p);
 }
 "#,
@@ -3625,7 +3626,7 @@
 fn minimized() {
     let v = V::default();
     let p = v.get();
-      //^ &{unknown}
+      //^ &'? {unknown}
     take_u32(42 + p);
 }
 "#,
@@ -3684,11 +3685,11 @@
 }
 "#,
         expect![[r#"
-            44..48 'self': &Self
-            133..137 'self': &[u8; 4]
+            44..48 'self': &'? Self
+            133..137 'self': &'? [u8; 4]
             155..172 '{     ...     }': usize
             165..166 '2': usize
-            236..240 'self': &[u8; 2]
+            236..240 'self': &'? [u8; 2]
             258..275 '{     ...     }': u8
             268..269 '2': u8
             289..392 '{     ...g(); }': ()
@@ -3732,11 +3733,11 @@
 }
 "#,
         expect![[r#"
-            44..48 'self': &Self
-            151..155 'self': &[u8; L]
+            44..48 'self': &'? Self
+            151..155 'self': &'? [u8; L]
             173..194 '{     ...     }': [u8; L]
             183..188 '*self': [u8; L]
-            184..188 'self': &[u8; L]
+            184..188 'self': &'? [u8; L]
             208..260 '{     ...g(); }': ()
             218..219 'v': [u8; 2]
             222..230 '[0u8; 2]': [u8; 2]
@@ -4056,13 +4057,13 @@
 }
         "#,
         expect![[r#"
-            68..69 't': &{unknown}
+            68..69 't': &'? {unknown}
             101..103 '{}': ()
-            109..110 't': &{unknown}
+            109..110 't': &'? {unknown}
             142..155 '{     f(t); }': ()
-            148..149 'f': fn f(&{unknown})
+            148..149 'f': fn f(&'? {unknown})
             148..152 'f(t)': ()
-            150..151 't': &{unknown}
+            150..151 't': &'? {unknown}
         "#]],
     );
 
@@ -4105,7 +4106,7 @@
 }
 
 fn f(t: &dyn Trait<T = (), T = ()>) {}
-   //^&{unknown}
+   //^&'? {unknown}
         "#,
     );
 }
@@ -4175,27 +4176,27 @@
 
 fn f<T>(v: impl Trait) {
     let a = v.get::<i32>().deref();
-      //^ &i32
+      //^ &'? i32
     let a = v.get::<T>().deref();
-      //^ &T
+      //^ &'? T
 }
 fn g<'a, T: 'a>(v: impl Trait<Assoc<T> = &'a T>) {
     let a = v.get::<T>();
-      //^ &T
+      //^ &'a T
     let a = v.get::<()>();
-      //^ Trait::Assoc<(), impl Trait<Assoc<T> = &T>>
+      //^ Trait::Assoc<(), impl Trait<Assoc<T> = &'a T>>
 }
 fn h<'a>(v: impl Trait<Assoc<i32> = &'a i32> + Trait<Assoc<i64> = &'a i64>) {
     let a = v.get::<i32>();
-      //^ &i32
+      //^ &'a i32
     let a = v.get::<i64>();
-      //^ &i64
+      //^ &'a i64
 }
 fn i<'a>(v: impl Trait<Assoc<i32> = &'a i32, Assoc<i64> = &'a i64>) {
     let a = v.get::<i32>();
-      //^ &i32
+      //^ &'a i32
     let a = v.get::<i64>();
-      //^ &i64
+      //^ &'a i64
 }
     "#,
     );
@@ -4221,12 +4222,12 @@
 }
     "#,
         expect![[r#"
-            90..94 'self': &Self
-            127..128 'v': &(dyn Trait<Assoc<i32> = &i32>)
+            90..94 'self': &'? Self
+            127..128 'v': &'? (dyn Trait<Assoc<i32> = &'a i32>)
             164..195 '{     ...f(); }': ()
-            170..171 'v': &(dyn Trait<Assoc<i32> = &i32>)
-            170..184 'v.get::<i32>()': &i32
-            170..192 'v.get:...eref()': &i32
+            170..171 'v': &'? (dyn Trait<Assoc<i32> = &'a i32>)
+            170..184 'v.get::<i32>()': &'? i32
+            170..192 'v.get:...eref()': &'? i32
         "#]],
     );
 }
@@ -4487,19 +4488,19 @@
             let x = (&Copy).clone();
               //^ Copy
             let x = (&NotCopy).clone();
-              //^ &NotCopy
+              //^ &'? NotCopy
             let x = (&Generic(Copy)).clone();
               //^ Generic<Copy>
             let x = (&Generic(NotCopy)).clone();
-              //^ &Generic<NotCopy>
+              //^ &'? Generic<NotCopy>
             let x: &AssocGeneric<Copy> = &AssocGeneric(NotCopy);
             let x = x.clone();
-              //^ &AssocGeneric<Copy>
+              //^ &'? AssocGeneric<Copy>
             // let x: &AssocGeneric2<Copy> = &AssocGeneric2(NotCopy);
             // let x = x.clone();
             let x: &AssocGeneric3<Copy> = &AssocGeneric3(Generic(NotCopy));
             let x = x.clone();
-              //^ &AssocGeneric3<Copy>
+              //^ &'? AssocGeneric3<Copy>
             let x = (&R1(Vec())).clone();
               //^ R1
             let x = (&R2(R1(Vec()))).clone();
@@ -4582,7 +4583,7 @@
 fn ttt() {
     let inp = Y;
     x::<u16>(&inp);
-           //^^^^ expected &X, got &Y
+           //^^^^ expected &'? X, got &'? Y
 }
 "#,
     );
@@ -4629,7 +4630,7 @@
     let mut map = SomeMap;
     map["a"] = ();
     map;
-  //^^^ SomeMap<&str>
+  //^^^ SomeMap<&'static str>
 }
 "#,
     );
@@ -4764,3 +4765,62 @@
         "#,
     );
 }
+
+#[test]
+fn associated_type_with_impl_trait_in_tuple() {
+    check_no_mismatches(
+        r#"
+pub trait Iterator {
+    type Item;
+}
+
+pub trait Value {}
+
+fn bar<I: Iterator<Item = (usize, impl Value)>>() {}
+
+fn foo() {
+    bar();
+}
+"#,
+    );
+}
+
+#[test]
+fn associated_type_with_impl_trait_in_nested_tuple() {
+    check_no_mismatches(
+        r#"
+pub trait Iterator {
+    type Item;
+}
+
+pub trait Value {}
+
+fn bar<I: Iterator<Item = ((impl Value, usize), u32)>>() {}
+
+fn foo() {
+    bar();
+}
+"#,
+    );
+}
+
+#[test]
+fn dyn_trait_with_lifetime_in_rpit() {
+    check_types(
+        r#"
+//- minicore: future
+pub struct Box<T> {}
+
+trait Trait {}
+
+pub async fn foo_async<'a>() -> Box<dyn Trait + 'a>  {
+    Box {}
+}
+
+fn foo() {
+    foo_async();
+  //^^^^^^^^^^^impl Future<Output = Box<dyn Trait>> + ?Sized
+}
+"#,
+    )
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 4518422..7227293 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -9,9 +9,11 @@
 use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
+pub use hir_def::VariantId;
 use hir_def::{body::SyntheticSyntax, hir::ExprOrPatId, path::ModPath, AssocItemId, DefWithBodyId};
 use hir_expand::{name::Name, HirFileId, InFile};
 use syntax::{ast, AstPtr, SyntaxError, SyntaxNodePtr, TextRange};
+use triomphe::Arc;
 
 use crate::{AssocItem, Field, Local, MacroKind, Trait, Type};
 
@@ -171,7 +173,7 @@
 pub struct MacroExpansionParseError {
     pub node: InFile<SyntaxNodePtr>,
     pub precise_location: Option<TextRange>,
-    pub errors: Box<[SyntaxError]>,
+    pub errors: Arc<[SyntaxError]>,
 }
 
 #[derive(Debug, Clone, Eq, PartialEq)]
@@ -200,6 +202,7 @@
 pub struct NoSuchField {
     pub field: InFile<AstPtr<Either<ast::RecordExprField, ast::RecordPatField>>>,
     pub private: bool,
+    pub variant: VariantId,
 }
 
 #[derive(Debug)]
@@ -525,7 +528,7 @@
             source_map.pat_syntax(pat).inspect_err(|_| tracing::error!("synthetic syntax")).ok()
         };
         Some(match d {
-            &InferenceDiagnostic::NoSuchField { field: expr, private } => {
+            &InferenceDiagnostic::NoSuchField { field: expr, private, variant } => {
                 let expr_or_pat = match expr {
                     ExprOrPatId::ExprId(expr) => {
                         source_map.field_syntax(expr).map(AstPtr::wrap_left)
@@ -534,7 +537,7 @@
                         source_map.pat_field_syntax(pat).map(AstPtr::wrap_right)
                     }
                 };
-                NoSuchField { field: expr_or_pat, private }.into()
+                NoSuchField { field: expr_or_pat, private, variant }.into()
             }
             &InferenceDiagnostic::MismatchedArgCount { call_expr, expected, found } => {
                 MismatchedArgCount { call_expr: expr_syntax(call_expr)?, expected, found }.into()
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 84f03d1..c276e87 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -188,28 +188,7 @@
             StructKind::Record => {
                 let has_where_clause = write_where_clause(def_id, f)?;
                 if let Some(limit) = f.entity_limit {
-                    let fields = self.fields(f.db);
-                    let count = fields.len().min(limit);
-                    f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
-                    if count == 0 {
-                        if fields.is_empty() {
-                            f.write_str("{}")?;
-                        } else {
-                            f.write_str("{ /* … */ }")?;
-                        }
-                    } else {
-                        f.write_str(" {\n")?;
-                        for field in &fields[..count] {
-                            f.write_str("    ")?;
-                            field.hir_fmt(f)?;
-                            f.write_str(",\n")?;
-                        }
-
-                        if fields.len() > count {
-                            f.write_str("    /* … */\n")?;
-                        }
-                        f.write_str("}")?;
-                    }
+                    display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?;
                 }
             }
             StructKind::Unit => _ = write_where_clause(def_id, f)?,
@@ -226,18 +205,10 @@
         write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
         let def_id = GenericDefId::AdtId(AdtId::EnumId(self.id));
         write_generic_params(def_id, f)?;
-        let has_where_clause = write_where_clause(def_id, f)?;
 
-        let variants = self.variants(f.db);
-        if !variants.is_empty() {
-            f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
-            f.write_str("{\n")?;
-            for variant in variants {
-                f.write_str("    ")?;
-                variant.hir_fmt(f)?;
-                f.write_str(",\n")?;
-            }
-            f.write_str("}")?;
+        let has_where_clause = write_where_clause(def_id, f)?;
+        if let Some(limit) = f.entity_limit {
+            display_variants(&self.variants(f.db), has_where_clause, limit, f)?;
         }
 
         Ok(())
@@ -251,24 +222,104 @@
         write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
         let def_id = GenericDefId::AdtId(AdtId::UnionId(self.id));
         write_generic_params(def_id, f)?;
+
         let has_where_clause = write_where_clause(def_id, f)?;
-
-        let fields = self.fields(f.db);
-        if !fields.is_empty() {
-            f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
-            f.write_str("{\n")?;
-            for field in self.fields(f.db) {
-                f.write_str("    ")?;
-                field.hir_fmt(f)?;
-                f.write_str(",\n")?;
-            }
-            f.write_str("}")?;
+        if let Some(limit) = f.entity_limit {
+            display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?;
         }
-
         Ok(())
     }
 }
 
+fn display_fields(
+    fields: &[Field],
+    has_where_clause: bool,
+    limit: usize,
+    in_line: bool,
+    f: &mut HirFormatter<'_>,
+) -> Result<(), HirDisplayError> {
+    let count = fields.len().min(limit);
+    let (indent, separator) = if in_line { ("", ' ') } else { ("    ", '\n') };
+    f.write_char(if !has_where_clause { ' ' } else { separator })?;
+    if count == 0 {
+        if fields.is_empty() {
+            f.write_str("{}")?;
+        } else {
+            f.write_str("{ /* … */ }")?;
+        }
+    } else {
+        f.write_char('{')?;
+
+        if !fields.is_empty() {
+            f.write_char(separator)?;
+            for field in &fields[..count] {
+                f.write_str(indent)?;
+                field.hir_fmt(f)?;
+                f.write_char(',')?;
+                f.write_char(separator)?;
+            }
+
+            if fields.len() > count {
+                f.write_str(indent)?;
+                f.write_str("/* … */")?;
+                f.write_char(separator)?;
+            }
+        }
+
+        f.write_str("}")?;
+    }
+
+    Ok(())
+}
+
+fn display_variants(
+    variants: &[Variant],
+    has_where_clause: bool,
+    limit: usize,
+    f: &mut HirFormatter<'_>,
+) -> Result<(), HirDisplayError> {
+    let count = variants.len().min(limit);
+    f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
+    if count == 0 {
+        if variants.is_empty() {
+            f.write_str("{}")?;
+        } else {
+            f.write_str("{ /* … */ }")?;
+        }
+    } else {
+        f.write_str("{\n")?;
+        for variant in &variants[..count] {
+            f.write_str("    ")?;
+            write!(f, "{}", variant.name(f.db).display(f.db.upcast()))?;
+            match variant.kind(f.db) {
+                StructKind::Tuple => {
+                    if variant.fields(f.db).is_empty() {
+                        f.write_str("()")?;
+                    } else {
+                        f.write_str("( /* … */ )")?;
+                    }
+                }
+                StructKind::Record => {
+                    if variant.fields(f.db).is_empty() {
+                        f.write_str(" {}")?;
+                    } else {
+                        f.write_str(" { /* … */ }")?;
+                    }
+                }
+                StructKind::Unit => {}
+            }
+            f.write_str(",\n")?;
+        }
+
+        if variants.len() > count {
+            f.write_str("    /* … */\n")?;
+        }
+        f.write_str("}")?;
+    }
+
+    Ok(())
+}
+
 impl HirDisplay for Field {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         write_visibility(self.parent.module(f.db).id, self.visibility(f.db), f)?;
@@ -304,21 +355,10 @@
                 }
                 f.write_char(')')?;
             }
-            VariantData::Record(fields) => {
-                f.write_str(" {")?;
-                let mut first = true;
-                for (_, field) in fields.iter() {
-                    if first {
-                        first = false;
-                        f.write_char(' ')?;
-                    } else {
-                        f.write_str(", ")?;
-                    }
-                    // Enum variant fields must be pub.
-                    write!(f, "{}: ", field.name.display(f.db.upcast()))?;
-                    field.type_ref.hir_fmt(f)?;
+            VariantData::Record(_) => {
+                if let Some(limit) = f.entity_limit {
+                    display_fields(&self.fields(f.db), false, limit, true, f)?;
                 }
-                f.write_str(" }")?;
             }
         }
         Ok(())
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index bcd94a6..85f33a1 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -59,7 +59,9 @@
     ModuleId, StaticId, StructId, TraitAliasId, TraitId, TupleId, TypeAliasId, TypeOrConstParamId,
     TypeParamId, UnionId,
 };
-use hir_expand::{attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, MacroCallKind};
+use hir_expand::{
+    attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, AstId, MacroCallKind, ValueResult,
+};
 use hir_ty::{
     all_super_traits, autoderef, check_orphan_rules,
     consteval::{try_const_usize, unknown_const_as_generic, ConstExt},
@@ -79,7 +81,7 @@
 use itertools::Itertools;
 use nameres::diagnostics::DefDiagnosticKind;
 use rustc_hash::FxHashSet;
-use span::Edition;
+use span::{Edition, MacroCallId};
 use stdx::{impl_from, never};
 use syntax::{
     ast::{self, HasAttrs as _, HasName},
@@ -559,6 +561,12 @@
             emit_def_diagnostic(db, acc, diag);
         }
 
+        if !self.id.is_block_module() {
+            // These are reported by the body of block modules
+            let scope = &def_map[self.id.local_id].scope;
+            scope.all_macro_calls().for_each(|it| macro_call_diagnostics(db, it, acc));
+        }
+
         for def in self.declarations(db) {
             match def {
                 ModuleDef::Module(m) => {
@@ -577,6 +585,10 @@
                         item.diagnostics(db, acc, style_lints);
                     }
 
+                    t.all_macro_calls(db)
+                        .iter()
+                        .for_each(|&(_ast, call_id)| macro_call_diagnostics(db, call_id, acc));
+
                     acc.extend(def.diagnostics(db, style_lints))
                 }
                 ModuleDef::Adt(adt) => {
@@ -621,6 +633,11 @@
                 // FIXME: Once we diagnose the inputs to builtin derives, we should at least extract those diagnostics somehow
                 continue;
             }
+            impl_def
+                .all_macro_calls(db)
+                .iter()
+                .for_each(|&(_ast, call_id)| macro_call_diagnostics(db, call_id, acc));
+
             let ast_id_map = db.ast_id_map(file_id);
 
             for diag in db.impl_data_with_diagnostics(impl_def.id).1.iter() {
@@ -809,6 +826,37 @@
     }
 }
 
+fn macro_call_diagnostics(
+    db: &dyn HirDatabase,
+    macro_call_id: MacroCallId,
+    acc: &mut Vec<AnyDiagnostic>,
+) {
+    let Some(e) = db.parse_macro_expansion_error(macro_call_id) else {
+        return;
+    };
+    let ValueResult { value: parse_errors, err } = &*e;
+    if let Some(err) = err {
+        let loc = db.lookup_intern_macro_call(macro_call_id);
+        let (node, precise_location, macro_name, kind) = precise_macro_call_location(&loc.kind, db);
+        let diag = match err {
+            &hir_expand::ExpandError::UnresolvedProcMacro(krate) => {
+                UnresolvedProcMacro { node, precise_location, macro_name, kind, krate }.into()
+            }
+            err => MacroError { node, precise_location, message: err.to_string() }.into(),
+        };
+        acc.push(diag);
+    }
+
+    if !parse_errors.is_empty() {
+        let loc = db.lookup_intern_macro_call(macro_call_id);
+        let (node, precise_location, _, _) = precise_macro_call_location(&loc.kind, db);
+        acc.push(
+            MacroExpansionParseError { node, precise_location, errors: parse_errors.clone() }
+                .into(),
+        )
+    }
+}
+
 fn emit_macro_def_diagnostics(db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>, m: Macro) {
     let id = db.macro_def(m.id);
     if let hir_expand::db::TokenExpander::DeclarativeMacro(expander) = db.macro_expander(id) {
@@ -888,16 +936,6 @@
                 .into(),
             );
         }
-        DefDiagnosticKind::MacroError { ast, message } => {
-            let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
-            acc.push(MacroError { node, precise_location, message: message.clone() }.into());
-        }
-        DefDiagnosticKind::MacroExpansionParseError { ast, errors } => {
-            let (node, precise_location, _, _) = precise_macro_call_location(ast, db);
-            acc.push(
-                MacroExpansionParseError { node, precise_location, errors: errors.clone() }.into(),
-            );
-        }
         DefDiagnosticKind::UnimplementedBuiltinMacro { ast } => {
             let node = ast.to_node(db.upcast());
             // Must have a name, otherwise we wouldn't emit it.
@@ -1489,6 +1527,14 @@
             .map(|arena| arena.1.clone())
     }
 
+    pub fn as_struct(&self) -> Option<Struct> {
+        if let Self::Struct(v) = self {
+            Some(*v)
+        } else {
+            None
+        }
+    }
+
     pub fn as_enum(&self) -> Option<Enum> {
         if let Self::Enum(v) = self {
             Some(*v)
@@ -1636,6 +1682,10 @@
             Module { id: def_map.module_id(DefMap::ROOT) }.diagnostics(db, acc, style_lints);
         }
 
+        source_map
+            .macro_calls()
+            .for_each(|(_ast_id, call_id)| macro_call_diagnostics(db, call_id.macro_call_id, acc));
+
         for diag in source_map.diagnostics() {
             acc.push(match diag {
                 BodyDiagnostic::InactiveCode { node, cfg, opts } => {
@@ -2437,6 +2487,14 @@
             .filter(|(_, ty)| !count_required_only || !ty.has_default())
             .count()
     }
+
+    fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
+        db.trait_data(self.id)
+            .macro_calls
+            .as_ref()
+            .map(|it| it.as_ref().clone().into_boxed_slice())
+            .unwrap_or_default()
+    }
 }
 
 impl HasVisibility for Trait {
@@ -2506,6 +2564,15 @@
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct StaticLifetime;
+
+impl StaticLifetime {
+    pub fn name(self) -> Name {
+        known::STATIC_LIFETIME
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct BuiltinType {
     pub(crate) inner: hir_def::builtin_type::BuiltinType,
 }
@@ -2535,6 +2602,20 @@
         matches!(self.inner, hir_def::builtin_type::BuiltinType::Float(_))
     }
 
+    pub fn is_f32(&self) -> bool {
+        matches!(
+            self.inner,
+            hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F32)
+        )
+    }
+
+    pub fn is_f64(&self) -> bool {
+        matches!(
+            self.inner,
+            hir_def::builtin_type::BuiltinType::Float(hir_def::builtin_type::BuiltinFloat::F64)
+        )
+    }
+
     pub fn is_char(&self) -> bool {
         matches!(self.inner, hir_def::builtin_type::BuiltinType::Char)
     }
@@ -3743,6 +3824,14 @@
     pub fn check_orphan_rules(self, db: &dyn HirDatabase) -> bool {
         check_orphan_rules(db, self.id)
     }
+
+    fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
+        db.impl_data(self.id)
+            .macro_calls
+            .as_ref()
+            .map(|it| it.as_ref().clone().into_boxed_slice())
+            .unwrap_or_default()
+    }
 }
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -4495,7 +4584,8 @@
         name: Option<&Name>,
         mut callback: impl FnMut(Function) -> Option<T>,
     ) -> Option<T> {
-        let _p = tracing::span!(tracing::Level::INFO, "iterate_method_candidates").entered();
+        let _p =
+            tracing::span!(tracing::Level::INFO, "iterate_method_candidates_with_traits").entered();
         let mut slot = None;
 
         self.iterate_method_candidates_dyn(
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index e792e15..6c70cc4 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -131,7 +131,7 @@
     pub db: &'db dyn HirDatabase,
     s2d_cache: RefCell<SourceToDefCache>,
     /// Rootnode to HirFileId cache
-    cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
+    root_to_file_cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
     // These 2 caches are mainly useful for semantic highlighting as nothing else descends a lot of tokens
     // So we might wanna move them out into something specific for semantic highlighting
     expansion_info_cache: RefCell<FxHashMap<MacroFileId, ExpansionInfo>>,
@@ -294,7 +294,7 @@
         SemanticsImpl {
             db,
             s2d_cache: Default::default(),
-            cache: Default::default(),
+            root_to_file_cache: Default::default(),
             expansion_info_cache: Default::default(),
             macro_call_cache: Default::default(),
         }
@@ -690,6 +690,7 @@
                 exp_info
             });
 
+            // FIXME: uncached parse
             // Create the source analyzer for the macro call scope
             let Some(sa) = self.analyze_no_infer(&self.parse_or_expand(expansion_info.call_file()))
             else {
@@ -722,7 +723,7 @@
         mut token: SyntaxToken,
         f: &mut dyn FnMut(InFile<SyntaxToken>) -> ControlFlow<()>,
     ) {
-        let _p = tracing::span!(tracing::Level::INFO, "descend_into_macros").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "descend_into_macros_impl").entered();
         let (sa, span, file_id) =
             match token.parent().and_then(|parent| self.analyze_no_infer(&parent)) {
                 Some(sa) => match sa.file_id.file_id() {
@@ -1025,6 +1026,7 @@
                 None => {
                     let call_node = file_id.macro_file()?.call_node(db);
                     // cache the node
+                    // FIXME: uncached parse
                     self.parse_or_expand(call_node.file_id);
                     Some(call_node)
                 }
@@ -1370,7 +1372,7 @@
         offset: Option<TextSize>,
         infer_body: bool,
     ) -> Option<SourceAnalyzer> {
-        let _p = tracing::span!(tracing::Level::INFO, "Semantics::analyze_impl").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "SemanticsImpl::analyze_impl").entered();
         let node = self.find_file(node);
 
         let container = self.with_ctx(|ctx| ctx.find_container(node))?;
@@ -1397,7 +1399,7 @@
 
     fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
         assert!(root_node.parent().is_none());
-        let mut cache = self.cache.borrow_mut();
+        let mut cache = self.root_to_file_cache.borrow_mut();
         let prev = cache.insert(root_node, file_id);
         assert!(prev.is_none() || prev == Some(file_id))
     }
@@ -1407,7 +1409,7 @@
     }
 
     fn lookup(&self, root_node: &SyntaxNode) -> Option<HirFileId> {
-        let cache = self.cache.borrow();
+        let cache = self.root_to_file_cache.borrow();
         cache.get(root_node).copied()
     }
 
@@ -1427,7 +1429,7 @@
                  known nodes: {}\n\n",
                 node,
                 root_node,
-                self.cache
+                self.root_to_file_cache
                     .borrow()
                     .keys()
                     .map(|it| format!("{it:?}"))
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index 434e4b5..d2bd8b0 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -118,10 +118,10 @@
 
 impl SourceToDefCtx<'_, '_> {
     pub(super) fn file_to_def(&self, file: FileId) -> SmallVec<[ModuleId; 1]> {
-        let _p = tracing::span!(tracing::Level::INFO, "SourceBinder::file_to_module_def").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "SourceToDefCtx::file_to_def").entered();
         let mut mods = SmallVec::new();
         for &crate_id in self.db.relevant_crates(file).iter() {
-            // FIXME: inner items
+            // Note: `mod` declarations in block modules cannot be supported here
             let crate_def_map = self.db.crate_def_map(crate_id);
             mods.extend(
                 crate_def_map
@@ -129,6 +129,9 @@
                     .map(|local_id| crate_def_map.module_id(local_id)),
             )
         }
+        if mods.is_empty() {
+            // FIXME: detached file
+        }
         mods
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index dc96a1b..057b03b 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -28,7 +28,7 @@
     mod_path::path,
     name,
     name::{AsName, Name},
-    HirFileId, InFile, MacroFileId, MacroFileIdExt,
+    HirFileId, InFile, InMacroFile, MacroFileId, MacroFileIdExt,
 };
 use hir_ty::{
     diagnostics::{
@@ -118,7 +118,7 @@
     fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
         let src = match expr {
             ast::Expr::MacroExpr(expr) => {
-                self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?
+                self.expand_expr(db, InFile::new(self.file_id, expr.macro_call()?))?.into()
             }
             _ => InFile::new(self.file_id, expr.clone()),
         };
@@ -145,20 +145,20 @@
         &self,
         db: &dyn HirDatabase,
         expr: InFile<ast::MacroCall>,
-    ) -> Option<InFile<ast::Expr>> {
+    ) -> Option<InMacroFile<ast::Expr>> {
         let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
-        let expanded = db.parse_or_expand(macro_file);
+        let expanded = db.parse_macro_expansion(macro_file).value.0.syntax_node();
         let res = if let Some(stmts) = ast::MacroStmts::cast(expanded.clone()) {
             match stmts.expr()? {
                 ast::Expr::MacroExpr(mac) => {
-                    self.expand_expr(db, InFile::new(macro_file, mac.macro_call()?))?
+                    self.expand_expr(db, InFile::new(macro_file.into(), mac.macro_call()?))?
                 }
-                expr => InFile::new(macro_file, expr),
+                expr => InMacroFile::new(macro_file, expr),
             }
         } else if let Some(call) = ast::MacroCall::cast(expanded.clone()) {
-            self.expand_expr(db, InFile::new(macro_file, call))?
+            self.expand_expr(db, InFile::new(macro_file.into(), call))?
         } else {
-            InFile::new(macro_file, ast::Expr::cast(expanded)?)
+            InMacroFile::new(macro_file, ast::Expr::cast(expanded)?)
         };
 
         Some(res)
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search.rs b/src/tools/rust-analyzer/crates/hir/src/term_search.rs
index 93e7300..5c5ddae 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search.rs
@@ -127,6 +127,13 @@
             self.types_wishlist.insert(ty.clone());
         }
 
+        // Collapse suggestions if there are many
+        if let Some(res) = &res {
+            if res.len() > self.many_threshold {
+                return Some(vec![Expr::Many(ty.clone())]);
+            }
+        }
+
         res
     }
 
@@ -158,6 +165,13 @@
             self.types_wishlist.insert(ty.clone());
         }
 
+        // Collapse suggestions if there are many
+        if let Some(res) = &res {
+            if res.len() > self.many_threshold {
+                return Some(vec![Expr::Many(ty.clone())]);
+            }
+        }
+
         res
     }
 
@@ -255,13 +269,13 @@
     pub enable_borrowcheck: bool,
     /// Indicate when to squash multiple trees to `Many` as there are too many to keep track
     pub many_alternatives_threshold: usize,
-    /// Depth of the search eg. number of cycles to run
-    pub depth: usize,
+    /// Fuel for term search in "units of work"
+    pub fuel: u64,
 }
 
 impl Default for TermSearchConfig {
     fn default() -> Self {
-        Self { enable_borrowcheck: true, many_alternatives_threshold: 1, depth: 6 }
+        Self { enable_borrowcheck: true, many_alternatives_threshold: 1, fuel: 400 }
     }
 }
 
@@ -280,8 +294,7 @@
 ///    transformation tactics. For example functions take as from set of types (arguments) to some
 ///    type (return type). Other transformations include methods on type, type constructors and
 ///    projections to struct fields (field access).
-/// 3. Once we manage to find path to type we are interested in we continue for single round to see
-///    if we can find more paths that take us to the `goal` type.
+/// 3. If we run out of fuel (term search takes too long) we stop iterating.
 /// 4. Return all the paths (type trees) that take us to the `goal` type.
 ///
 /// Note that there are usually more ways we can get to the `goal` type but some are discarded to
@@ -297,21 +310,31 @@
     });
 
     let mut lookup = LookupTable::new(ctx.config.many_alternatives_threshold, ctx.goal.clone());
+    let fuel = std::cell::Cell::new(ctx.config.fuel);
+
+    let should_continue = &|| {
+        let remaining = fuel.get();
+        fuel.set(remaining.saturating_sub(1));
+        if remaining == 0 {
+            tracing::debug!("fuel exhausted");
+        }
+        remaining > 0
+    };
 
     // Try trivial tactic first, also populates lookup table
     let mut solutions: Vec<Expr> = tactics::trivial(ctx, &defs, &mut lookup).collect();
     // Use well known types tactic before iterations as it does not depend on other tactics
     solutions.extend(tactics::famous_types(ctx, &defs, &mut lookup));
 
-    for _ in 0..ctx.config.depth {
+    while should_continue() {
         lookup.new_round();
 
-        solutions.extend(tactics::type_constructor(ctx, &defs, &mut lookup));
-        solutions.extend(tactics::free_function(ctx, &defs, &mut lookup));
-        solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup));
-        solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup));
-        solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup));
-        solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup));
+        solutions.extend(tactics::type_constructor(ctx, &defs, &mut lookup, should_continue));
+        solutions.extend(tactics::free_function(ctx, &defs, &mut lookup, should_continue));
+        solutions.extend(tactics::impl_method(ctx, &defs, &mut lookup, should_continue));
+        solutions.extend(tactics::struct_projection(ctx, &defs, &mut lookup, should_continue));
+        solutions.extend(tactics::impl_static_method(ctx, &defs, &mut lookup, should_continue));
+        solutions.extend(tactics::make_tuple(ctx, &defs, &mut lookup, should_continue));
 
         // Discard not interesting `ScopeDef`s for speedup
         for def in lookup.exhausted_scopedefs() {
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
index 2d0c563..9f56a1e 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/expr.rs
@@ -211,13 +211,13 @@
                 }
             }
             Expr::Method { func, target, params, .. } => {
-                if target.contains_many_in_illegal_pos() {
+                if self.contains_many_in_illegal_pos(db) {
                     return Ok(many_formatter(&target.ty(db)));
                 }
 
                 let func_name = func.name(db).display(db.upcast()).to_string();
                 let self_param = func.self_param(db).unwrap();
-                let target = target.gen_source_code(
+                let target_str = target.gen_source_code(
                     sema_scope,
                     many_formatter,
                     prefer_no_std,
@@ -236,9 +236,12 @@
                     Some(trait_) => {
                         let trait_name = mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_))?;
                         let target = match self_param.access(db) {
-                            crate::Access::Shared => format!("&{target}"),
-                            crate::Access::Exclusive => format!("&mut {target}"),
-                            crate::Access::Owned => target,
+                            crate::Access::Shared if !target.is_many() => format!("&{target_str}"),
+                            crate::Access::Exclusive if !target.is_many() => {
+                                format!("&mut {target_str}")
+                            }
+                            crate::Access::Owned => target_str,
+                            _ => many_formatter(&target.ty(db)),
                         };
                         let res = match args.is_empty() {
                             true => format!("{trait_name}::{func_name}({target})",),
@@ -246,7 +249,7 @@
                         };
                         Ok(res)
                     }
-                    None => Ok(format!("{target}.{func_name}({args})")),
+                    None => Ok(format!("{target_str}.{func_name}({args})")),
                 }
             }
             Expr::Variant { variant, generics, params } => {
@@ -381,7 +384,7 @@
                 Ok(res)
             }
             Expr::Field { expr, field } => {
-                if expr.contains_many_in_illegal_pos() {
+                if expr.contains_many_in_illegal_pos(db) {
                     return Ok(many_formatter(&expr.ty(db)));
                 }
 
@@ -395,7 +398,7 @@
                 Ok(format!("{strukt}.{field}"))
             }
             Expr::Reference(expr) => {
-                if expr.contains_many_in_illegal_pos() {
+                if expr.contains_many_in_illegal_pos(db) {
                     return Ok(many_formatter(&expr.ty(db)));
                 }
 
@@ -466,10 +469,15 @@
     /// macro!().bar()
     /// &macro!()
     /// ```
-    fn contains_many_in_illegal_pos(&self) -> bool {
+    fn contains_many_in_illegal_pos(&self, db: &dyn HirDatabase) -> bool {
         match self {
-            Expr::Method { target, .. } => target.contains_many_in_illegal_pos(),
-            Expr::Field { expr, .. } => expr.contains_many_in_illegal_pos(),
+            Expr::Method { target, func, .. } => {
+                match func.as_assoc_item(db).and_then(|it| it.container_or_implemented_trait(db)) {
+                    Some(_) => false,
+                    None => target.is_many(),
+                }
+            }
+            Expr::Field { expr, .. } => expr.contains_many_in_illegal_pos(db),
             Expr::Reference(target) => target.is_many(),
             Expr::Many(_) => true,
             _ => false,
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
index 63b2a25..a267282 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
@@ -4,6 +4,7 @@
 //! * `ctx` - Context for the term search
 //! * `defs` - Set of items in scope at term search target location
 //! * `lookup` - Lookup table for types
+//! * `should_continue` - Function that indicates when to stop iterating
 //! And they return iterator that yields type trees that unify with the `goal` type.
 
 use std::iter;
@@ -97,16 +98,19 @@
 /// * `ctx` - Context for the term search
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
+/// * `should_continue` - Function that indicates when to stop iterating
 pub(super) fn type_constructor<'a, DB: HirDatabase>(
     ctx: &'a TermSearchCtx<'a, DB>,
     defs: &'a FxHashSet<ScopeDef>,
     lookup: &'a mut LookupTable,
+    should_continue: &'a dyn std::ops::Fn() -> bool,
 ) -> impl Iterator<Item = Expr> + 'a {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
     fn variant_helper(
         db: &dyn HirDatabase,
         lookup: &mut LookupTable,
+        should_continue: &dyn std::ops::Fn() -> bool,
         parent_enum: Enum,
         variant: Variant,
         config: &TermSearchConfig,
@@ -152,6 +156,7 @@
             .chain((non_default_type_params_len == 0).then_some(Vec::new()));
 
         generic_params
+            .filter(|_| should_continue())
             .filter_map(move |generics| {
                 // Insert default type params
                 let mut g = generics.into_iter();
@@ -194,8 +199,14 @@
     defs.iter()
         .filter_map(move |def| match def {
             ScopeDef::ModuleDef(ModuleDef::Variant(it)) => {
-                let variant_exprs =
-                    variant_helper(db, lookup, it.parent_enum(db), *it, &ctx.config);
+                let variant_exprs = variant_helper(
+                    db,
+                    lookup,
+                    should_continue,
+                    it.parent_enum(db),
+                    *it,
+                    &ctx.config,
+                );
                 if variant_exprs.is_empty() {
                     return None;
                 }
@@ -213,7 +224,9 @@
                 let exprs: Vec<(Type, Vec<Expr>)> = enum_
                     .variants(db)
                     .into_iter()
-                    .flat_map(|it| variant_helper(db, lookup, *enum_, it, &ctx.config))
+                    .flat_map(|it| {
+                        variant_helper(db, lookup, should_continue, *enum_, it, &ctx.config)
+                    })
                     .collect();
 
                 if exprs.is_empty() {
@@ -271,6 +284,7 @@
                     .chain((non_default_type_params_len == 0).then_some(Vec::new()));
 
                 let exprs = generic_params
+                    .filter(|_| should_continue())
                     .filter_map(|generics| {
                         // Insert default type params
                         let mut g = generics.into_iter();
@@ -345,10 +359,12 @@
 /// * `ctx` - Context for the term search
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
+/// * `should_continue` - Function that indicates when to stop iterating
 pub(super) fn free_function<'a, DB: HirDatabase>(
     ctx: &'a TermSearchCtx<'a, DB>,
     defs: &'a FxHashSet<ScopeDef>,
     lookup: &'a mut LookupTable,
+    should_continue: &'a dyn std::ops::Fn() -> bool,
 ) -> impl Iterator<Item = Expr> + 'a {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
@@ -390,6 +406,7 @@
                     .permutations(non_default_type_params_len);
 
                 let exprs: Vec<_> = generic_params
+                    .filter(|_| should_continue())
                     .filter_map(|generics| {
                         // Insert default type params
                         let mut g = generics.into_iter();
@@ -474,10 +491,12 @@
 /// * `ctx` - Context for the term search
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
+/// * `should_continue` - Function that indicates when to stop iterating
 pub(super) fn impl_method<'a, DB: HirDatabase>(
     ctx: &'a TermSearchCtx<'a, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
     lookup: &'a mut LookupTable,
+    should_continue: &'a dyn std::ops::Fn() -> bool,
 ) -> impl Iterator<Item = Expr> + 'a {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
@@ -554,6 +573,7 @@
                 .permutations(non_default_fn_type_params_len);
 
             let exprs: Vec<_> = generic_params
+                .filter(|_| should_continue())
                 .filter_map(|generics| {
                     // Insert default type params
                     let mut g = generics.into_iter();
@@ -645,10 +665,12 @@
 /// * `ctx` - Context for the term search
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
+/// * `should_continue` - Function that indicates when to stop iterating
 pub(super) fn struct_projection<'a, DB: HirDatabase>(
     ctx: &'a TermSearchCtx<'a, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
     lookup: &'a mut LookupTable,
+    should_continue: &'a dyn std::ops::Fn() -> bool,
 ) -> impl Iterator<Item = Expr> + 'a {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
@@ -656,6 +678,7 @@
         .new_types(NewTypesKey::StructProjection)
         .into_iter()
         .map(|ty| (ty.clone(), lookup.find(db, &ty).expect("Expr not in lookup")))
+        .filter(|_| should_continue())
         .flat_map(move |(ty, targets)| {
             ty.fields(db).into_iter().filter_map(move |(field, filed_ty)| {
                 if !field.is_visible_from(db, module) {
@@ -716,10 +739,12 @@
 /// * `ctx` - Context for the term search
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
+/// * `should_continue` - Function that indicates when to stop iterating
 pub(super) fn impl_static_method<'a, DB: HirDatabase>(
     ctx: &'a TermSearchCtx<'a, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
     lookup: &'a mut LookupTable,
+    should_continue: &'a dyn std::ops::Fn() -> bool,
 ) -> impl Iterator<Item = Expr> + 'a {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
@@ -728,6 +753,7 @@
         .clone()
         .into_iter()
         .chain(iter::once(ctx.goal.clone()))
+        .filter(|_| should_continue())
         .flat_map(|ty| {
             Impl::all_for_type(db, ty.clone()).into_iter().map(move |imp| (ty.clone(), imp))
         })
@@ -801,6 +827,7 @@
                 .permutations(non_default_fn_type_params_len);
 
             let exprs: Vec<_> = generic_params
+                .filter(|_| should_continue())
                 .filter_map(|generics| {
                     // Insert default type params
                     let mut g = generics.into_iter();
@@ -884,10 +911,12 @@
 /// * `ctx` - Context for the term search
 /// * `defs` - Set of items in scope at term search target location
 /// * `lookup` - Lookup table for types
+/// * `should_continue` - Function that indicates when to stop iterating
 pub(super) fn make_tuple<'a, DB: HirDatabase>(
     ctx: &'a TermSearchCtx<'a, DB>,
     _defs: &'a FxHashSet<ScopeDef>,
     lookup: &'a mut LookupTable,
+    should_continue: &'a dyn std::ops::Fn() -> bool,
 ) -> impl Iterator<Item = Expr> + 'a {
     let db = ctx.sema.db;
     let module = ctx.scope.module();
@@ -896,6 +925,7 @@
         .types_wishlist()
         .clone()
         .into_iter()
+        .filter(|_| should_continue())
         .filter(|ty| ty.is_tuple())
         .filter_map(move |ty| {
             // Double check to not contain unknown
@@ -915,6 +945,7 @@
             let exprs: Vec<Expr> = param_exprs
                 .into_iter()
                 .multi_cartesian_product()
+                .filter(|_| should_continue())
                 .map(|params| {
                     let tys: Vec<Type> = params.iter().map(|it| it.ty(db)).collect();
                     let tuple_ty = Type::new_tuple(module.krate().into(), &tys);
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
index fbe17db..5d76cb0 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
@@ -16,4 +16,5 @@
     pub prefer_no_std: bool,
     pub prefer_prelude: bool,
     pub assist_emit_must_use: bool,
+    pub term_search_fuel: u64,
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
index 55e0d7f..f178a7e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
@@ -8,8 +8,7 @@
 };
 use syntax::{
     ast::{self, make, AstNode, Expr::BinExpr, HasArgList},
-    ted::{self, Position},
-    SyntaxKind,
+    ted, SyntaxKind, T,
 };
 
 use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKind, Assists};
@@ -62,7 +61,7 @@
     let demorganed = bin_expr.clone_subtree().clone_for_update();
 
     ted::replace(demorganed.op_token()?, ast::make::token(inv_token));
-    let mut exprs = VecDeque::from(vec![
+    let mut exprs = VecDeque::from([
         (bin_expr.lhs()?, demorganed.lhs()?),
         (bin_expr.rhs()?, demorganed.rhs()?),
     ]);
@@ -93,58 +92,38 @@
         }
     }
 
-    let dm_lhs = demorganed.lhs()?;
-
     acc.add_group(
         &GroupLabel("Apply De Morgan's law".to_owned()),
         AssistId("apply_demorgan", AssistKind::RefactorRewrite),
         "Apply De Morgan's law",
         op_range,
         |edit| {
+            let demorganed = ast::Expr::BinExpr(demorganed);
             let paren_expr = bin_expr.syntax().parent().and_then(ast::ParenExpr::cast);
             let neg_expr = paren_expr
                 .clone()
                 .and_then(|paren_expr| paren_expr.syntax().parent())
                 .and_then(ast::PrefixExpr::cast)
-                .and_then(|prefix_expr| {
-                    if prefix_expr.op_kind()? == ast::UnaryOp::Not {
-                        Some(prefix_expr)
-                    } else {
-                        None
-                    }
-                });
+                .filter(|prefix_expr| matches!(prefix_expr.op_kind(), Some(ast::UnaryOp::Not)))
+                .map(ast::Expr::PrefixExpr);
 
             if let Some(paren_expr) = paren_expr {
                 if let Some(neg_expr) = neg_expr {
                     cov_mark::hit!(demorgan_double_negation);
-                    edit.replace_ast(ast::Expr::PrefixExpr(neg_expr), demorganed.into());
+                    let parent = neg_expr.syntax().parent();
+
+                    if parent.is_some_and(|parent| demorganed.needs_parens_in(parent)) {
+                        cov_mark::hit!(demorgan_keep_parens_for_op_precedence2);
+                        edit.replace_ast(neg_expr, make::expr_paren(demorganed));
+                    } else {
+                        edit.replace_ast(neg_expr, demorganed);
+                    };
                 } else {
                     cov_mark::hit!(demorgan_double_parens);
-                    ted::insert_all_raw(
-                        Position::before(dm_lhs.syntax()),
-                        vec![
-                            syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::BANG)),
-                            syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::L_PAREN)),
-                        ],
-                    );
-
-                    ted::append_child_raw(
-                        demorganed.syntax(),
-                        syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::R_PAREN)),
-                    );
-
-                    edit.replace_ast(ast::Expr::ParenExpr(paren_expr), demorganed.into());
+                    edit.replace_ast(paren_expr.into(), add_bang_paren(demorganed));
                 }
             } else {
-                ted::insert_all_raw(
-                    Position::before(dm_lhs.syntax()),
-                    vec![
-                        syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::BANG)),
-                        syntax::NodeOrToken::Token(ast::make::token(SyntaxKind::L_PAREN)),
-                    ],
-                );
-                ted::append_child_raw(demorganed.syntax(), ast::make::token(SyntaxKind::R_PAREN));
-                edit.replace_ast(bin_expr, demorganed);
+                edit.replace_ast(bin_expr.into(), add_bang_paren(demorganed));
             }
         },
     )
@@ -271,6 +250,11 @@
     }
 }
 
+/// Add bang and parentheses to the expression.
+fn add_bang_paren(expr: ast::Expr) -> ast::Expr {
+    make::expr_prefix(T![!], make::expr_paren(expr))
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
@@ -349,16 +333,14 @@
         check_assist(apply_demorgan, "fn f() { (x ||$0 x) }", "fn f() { !(!x && !x) }")
     }
 
-    // FIXME : This needs to go.
-    // // https://github.com/rust-lang/rust-analyzer/issues/10963
-    // #[test]
-    // fn demorgan_doesnt_hang() {
-    //     check_assist(
-    //         apply_demorgan,
-    //         "fn f() { 1 || 3 &&$0 4 || 5 }",
-    //         "fn f() { !(!1 || !3 || !4) || 5 }",
-    //     )
-    // }
+    #[test]
+    fn demorgan_doesnt_hang() {
+        check_assist(
+            apply_demorgan,
+            "fn f() { 1 || 3 &&$0 4 || 5 }",
+            "fn f() { 1 || !(!3 || !4) || 5 }",
+        )
+    }
 
     #[test]
     fn demorgan_keep_pars_for_op_precedence() {
@@ -376,6 +358,21 @@
     }
 
     #[test]
+    fn demorgan_keep_pars_for_op_precedence2() {
+        cov_mark::check!(demorgan_keep_parens_for_op_precedence2);
+        check_assist(
+            apply_demorgan,
+            "fn f() { (a && !(b &&$0 c); }",
+            "fn f() { (a && (!b || !c); }",
+        );
+    }
+
+    #[test]
+    fn demorgan_keep_pars_for_op_precedence3() {
+        check_assist(apply_demorgan, "fn f() { (a || !(b &&$0 c); }", "fn f() { (a || !b || !c; }");
+    }
+
+    #[test]
     fn demorgan_removes_pars_in_eq_precedence() {
         check_assist(
             apply_demorgan,
@@ -385,6 +382,11 @@
     }
 
     #[test]
+    fn demorgan_removes_pars_for_op_precedence2() {
+        check_assist(apply_demorgan, "fn f() { (a || !(b ||$0 c); }", "fn f() { (a || !b && !c; }");
+    }
+
+    #[test]
     fn demorgan_iterator_any_all_reverse() {
         check_assist(
             apply_demorgan_iterator,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
index 76f021e..43ff115 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_named_struct_to_tuple_struct.rs
@@ -85,7 +85,7 @@
     strukt: &Either<ast::Struct, ast::Variant>,
     record_fields: ast::RecordFieldList,
 ) {
-    // Note that we don't need to consider macro files in this function because this this is
+    // Note that we don't need to consider macro files in this function because this is
     // currently not triggered for struct definitions inside macro calls.
     let tuple_fields = record_fields
         .fields()
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
index 3432629..2b8de34 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
@@ -5623,7 +5623,7 @@
     fun_name(i);
 }
 
-fn $0fun_name(i: Struct<'_, T>) {
+fn $0fun_name(i: Struct<T>) {
     foo(i);
 }
 "#,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
index db94a21..0fc122d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
@@ -1,6 +1,6 @@
 use hir::{
-    Adt, AsAssocItem, HasSource, HirDisplay, HirFileIdExt, Module, PathResolution, Semantics, Type,
-    TypeInfo,
+    Adt, AsAssocItem, HasSource, HirDisplay, HirFileIdExt, Module, PathResolution, Semantics,
+    StructKind, Type, TypeInfo,
 };
 use ide_db::{
     base_db::FileId,
@@ -15,8 +15,8 @@
 use stdx::to_lower_snake_case;
 use syntax::{
     ast::{
-        self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, CallExpr, HasArgList,
-        HasGenericParams, HasModuleItem, HasTypeBounds,
+        self, edit::IndentLevel, edit_in_place::Indent, make, AstNode, BlockExpr, CallExpr,
+        HasArgList, HasGenericParams, HasModuleItem, HasTypeBounds,
     },
     ted, SyntaxKind, SyntaxNode, TextRange, T,
 };
@@ -66,7 +66,7 @@
     }
 
     let fn_name = &*name_ref.text();
-    let TargetInfo { target_module, adt_name, target, file } =
+    let TargetInfo { target_module, adt_info, target, file } =
         fn_target_info(ctx, path, &call, fn_name)?;
 
     if let Some(m) = target_module {
@@ -75,15 +75,16 @@
         }
     }
 
-    let function_builder = FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target)?;
+    let function_builder =
+        FunctionBuilder::from_call(ctx, &call, fn_name, target_module, target, &adt_info)?;
     let text_range = call.syntax().text_range();
     let label = format!("Generate {} function", function_builder.fn_name);
-    add_func_to_accumulator(acc, ctx, text_range, function_builder, file, adt_name, label)
+    add_func_to_accumulator(acc, ctx, text_range, function_builder, file, adt_info, label)
 }
 
 struct TargetInfo {
     target_module: Option<Module>,
-    adt_name: Option<hir::Name>,
+    adt_info: Option<AdtInfo>,
     target: GeneratedFunctionTarget,
     file: FileId,
 }
@@ -91,11 +92,11 @@
 impl TargetInfo {
     fn new(
         target_module: Option<Module>,
-        adt_name: Option<hir::Name>,
+        adt_info: Option<AdtInfo>,
         target: GeneratedFunctionTarget,
         file: FileId,
     ) -> Self {
-        Self { target_module, adt_name, target, file }
+        Self { target_module, adt_info, target, file }
     }
 }
 
@@ -157,9 +158,9 @@
         target,
     )?;
     let text_range = call.syntax().text_range();
-    let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
+    let adt_info = AdtInfo::new(adt, impl_.is_some());
     let label = format!("Generate {} method", function_builder.fn_name);
-    add_func_to_accumulator(acc, ctx, text_range, function_builder, file, adt_name, label)
+    add_func_to_accumulator(acc, ctx, text_range, function_builder, file, Some(adt_info), label)
 }
 
 fn add_func_to_accumulator(
@@ -168,7 +169,7 @@
     text_range: TextRange,
     function_builder: FunctionBuilder,
     file: FileId,
-    adt_name: Option<hir::Name>,
+    adt_info: Option<AdtInfo>,
     label: String,
 ) -> Option<()> {
     acc.add(AssistId("generate_function", AssistKind::Generate), label, text_range, |edit| {
@@ -177,8 +178,14 @@
         let target = function_builder.target.clone();
         let func = function_builder.render(ctx.config.snippet_cap, edit);
 
-        if let Some(name) = adt_name {
-            let name = make::ty_path(make::ext::ident_path(&format!("{}", name.display(ctx.db()))));
+        if let Some(adt) =
+            adt_info
+                .and_then(|adt_info| if adt_info.impl_exists { None } else { Some(adt_info.adt) })
+        {
+            let name = make::ty_path(make::ext::ident_path(&format!(
+                "{}",
+                adt.name(ctx.db()).display(ctx.db())
+            )));
 
             // FIXME: adt may have generic params.
             let impl_ = make::impl_(None, None, name, None, None).clone_for_update();
@@ -210,6 +217,7 @@
     generic_param_list: Option<ast::GenericParamList>,
     where_clause: Option<ast::WhereClause>,
     params: ast::ParamList,
+    fn_body: BlockExpr,
     ret_type: Option<ast::RetType>,
     should_focus_return_type: bool,
     visibility: Visibility,
@@ -225,6 +233,7 @@
         fn_name: &str,
         target_module: Option<Module>,
         target: GeneratedFunctionTarget,
+        adt_info: &Option<AdtInfo>,
     ) -> Option<Self> {
         let target_module =
             target_module.or_else(|| ctx.sema.scope(target.syntax()).map(|it| it.module()))?;
@@ -243,9 +252,27 @@
         let await_expr = call.syntax().parent().and_then(ast::AwaitExpr::cast);
         let is_async = await_expr.is_some();
 
-        let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into());
-        let (ret_type, should_focus_return_type) =
-            make_return_type(ctx, &expr_for_ret_ty, target_module, &mut necessary_generic_params);
+        let ret_type;
+        let should_focus_return_type;
+        let fn_body;
+
+        // If generated function has the name "new" and is an associated function, we generate fn body
+        // as a constructor and assume a "Self" return type.
+        if let Some(body) = make_fn_body_as_new_function(ctx, &fn_name.text(), adt_info) {
+            ret_type = Some(make::ret_type(make::ty_path(make::ext::ident_path("Self"))));
+            should_focus_return_type = false;
+            fn_body = body;
+        } else {
+            let expr_for_ret_ty = await_expr.map_or_else(|| call.clone().into(), |it| it.into());
+            (ret_type, should_focus_return_type) = make_return_type(
+                ctx,
+                &expr_for_ret_ty,
+                target_module,
+                &mut necessary_generic_params,
+            );
+            let placeholder_expr = make::ext::expr_todo();
+            fn_body = make::block_expr(vec![], Some(placeholder_expr));
+        };
 
         let (generic_param_list, where_clause) =
             fn_generic_params(ctx, necessary_generic_params, &target)?;
@@ -256,6 +283,7 @@
             generic_param_list,
             where_clause,
             params,
+            fn_body,
             ret_type,
             should_focus_return_type,
             visibility,
@@ -294,12 +322,16 @@
         let (generic_param_list, where_clause) =
             fn_generic_params(ctx, necessary_generic_params, &target)?;
 
+        let placeholder_expr = make::ext::expr_todo();
+        let fn_body = make::block_expr(vec![], Some(placeholder_expr));
+
         Some(Self {
             target,
             fn_name,
             generic_param_list,
             where_clause,
             params,
+            fn_body,
             ret_type,
             should_focus_return_type,
             visibility,
@@ -308,8 +340,6 @@
     }
 
     fn render(self, cap: Option<SnippetCap>, edit: &mut SourceChangeBuilder) -> ast::Fn {
-        let placeholder_expr = make::ext::expr_todo();
-        let fn_body = make::block_expr(vec![], Some(placeholder_expr));
         let visibility = match self.visibility {
             Visibility::None => None,
             Visibility::Crate => Some(make::visibility_pub_crate()),
@@ -321,7 +351,7 @@
             self.generic_param_list,
             self.where_clause,
             self.params,
-            fn_body,
+            self.fn_body,
             self.ret_type,
             self.is_async,
             false, // FIXME : const and unsafe are not handled yet.
@@ -391,6 +421,53 @@
     (ret_type, should_focus_return_type)
 }
 
+fn make_fn_body_as_new_function(
+    ctx: &AssistContext<'_>,
+    fn_name: &str,
+    adt_info: &Option<AdtInfo>,
+) -> Option<ast::BlockExpr> {
+    if fn_name != "new" {
+        return None;
+    };
+    let adt_info = adt_info.as_ref()?;
+
+    let path_self = make::ext::ident_path("Self");
+    let placeholder_expr = make::ext::expr_todo();
+    let tail_expr = if let Some(strukt) = adt_info.adt.as_struct() {
+        match strukt.kind(ctx.db()) {
+            StructKind::Record => {
+                let fields = strukt
+                    .fields(ctx.db())
+                    .iter()
+                    .map(|field| {
+                        make::record_expr_field(
+                            make::name_ref(&format!("{}", field.name(ctx.db()).display(ctx.db()))),
+                            Some(placeholder_expr.clone()),
+                        )
+                    })
+                    .collect::<Vec<_>>();
+
+                make::record_expr(path_self, make::record_expr_field_list(fields)).into()
+            }
+            StructKind::Tuple => {
+                let args = strukt
+                    .fields(ctx.db())
+                    .iter()
+                    .map(|_| placeholder_expr.clone())
+                    .collect::<Vec<_>>();
+
+                make::expr_call(make::expr_path(path_self), make::arg_list(args))
+            }
+            StructKind::Unit => make::expr_path(path_self),
+        }
+    } else {
+        placeholder_expr
+    };
+
+    let fn_body = make::block_expr(vec![], Some(tail_expr));
+    Some(fn_body)
+}
+
 fn get_fn_target_info(
     ctx: &AssistContext<'_>,
     target_module: Option<Module>,
@@ -443,8 +520,8 @@
     }
     let (impl_, file) = get_adt_source(ctx, &adt, fn_name)?;
     let target = get_method_target(ctx, &impl_, &adt)?;
-    let adt_name = if impl_.is_none() { Some(adt.name(ctx.sema.db)) } else { None };
-    Some(TargetInfo::new(target_module, adt_name, target, file))
+    let adt_info = AdtInfo::new(adt, impl_.is_some());
+    Some(TargetInfo::new(target_module, Some(adt_info), target, file))
 }
 
 #[derive(Clone)]
@@ -560,6 +637,17 @@
     }
 }
 
+struct AdtInfo {
+    adt: hir::Adt,
+    impl_exists: bool,
+}
+
+impl AdtInfo {
+    fn new(adt: Adt, impl_exists: bool) -> Self {
+        Self { adt, impl_exists }
+    }
+}
+
 /// Computes parameter list for the generated function.
 fn fn_args(
     ctx: &AssistContext<'_>,
@@ -2758,18 +2846,18 @@
             r"
 enum Foo {}
 fn main() {
-    Foo::new$0();
+    Foo::bar$0();
 }
 ",
             r"
 enum Foo {}
 impl Foo {
-    fn new() ${0:-> _} {
+    fn bar() ${0:-> _} {
         todo!()
     }
 }
 fn main() {
-    Foo::new();
+    Foo::bar();
 }
 ",
         )
@@ -2849,4 +2937,152 @@
 ",
         );
     }
+
+    #[test]
+    fn new_function_assume_self_type() {
+        check_assist(
+            generate_function,
+            r"
+pub struct Foo {
+    field_1: usize,
+    field_2: String,
+}
+
+fn main() {
+    let foo = Foo::new$0();
+}
+        ",
+            r"
+pub struct Foo {
+    field_1: usize,
+    field_2: String,
+}
+impl Foo {
+    fn new() -> Self {
+        ${0:Self { field_1: todo!(), field_2: todo!() }}
+    }
+}
+
+fn main() {
+    let foo = Foo::new();
+}
+        ",
+        )
+    }
+
+    #[test]
+    fn new_function_assume_self_type_for_tuple_struct() {
+        check_assist(
+            generate_function,
+            r"
+pub struct Foo (usize, String);
+
+fn main() {
+    let foo = Foo::new$0();
+}
+        ",
+            r"
+pub struct Foo (usize, String);
+impl Foo {
+    fn new() -> Self {
+        ${0:Self(todo!(), todo!())}
+    }
+}
+
+fn main() {
+    let foo = Foo::new();
+}
+        ",
+        )
+    }
+
+    #[test]
+    fn new_function_assume_self_type_for_unit_struct() {
+        check_assist(
+            generate_function,
+            r"
+pub struct Foo;
+
+fn main() {
+    let foo = Foo::new$0();
+}
+        ",
+            r"
+pub struct Foo;
+impl Foo {
+    fn new() -> Self {
+        ${0:Self}
+    }
+}
+
+fn main() {
+    let foo = Foo::new();
+}
+        ",
+        )
+    }
+
+    #[test]
+    fn new_function_assume_self_type_for_enum() {
+        check_assist(
+            generate_function,
+            r"
+pub enum Foo {}
+
+fn main() {
+    let foo = Foo::new$0();
+}
+        ",
+            r"
+pub enum Foo {}
+impl Foo {
+    fn new() -> Self {
+        ${0:todo!()}
+    }
+}
+
+fn main() {
+    let foo = Foo::new();
+}
+        ",
+        )
+    }
+
+    #[test]
+    fn new_function_assume_self_type_with_args() {
+        check_assist(
+            generate_function,
+            r#"
+pub struct Foo {
+    field_1: usize,
+    field_2: String,
+}
+
+struct Baz;
+fn baz() -> Baz { Baz }
+
+fn main() {
+    let foo = Foo::new$0(baz(), baz(), "foo", "bar");
+}
+        "#,
+            r#"
+pub struct Foo {
+    field_1: usize,
+    field_2: String,
+}
+impl Foo {
+    fn new(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) -> Self {
+        ${0:Self { field_1: todo!(), field_2: todo!() }}
+    }
+}
+
+struct Baz;
+fn baz() -> Baz { Baz }
+
+fn main() {
+    let foo = Foo::new(baz(), baz(), "foo", "bar");
+}
+        "#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
index 048906d..9af8411 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
@@ -1,6 +1,7 @@
 use std::iter;
 
 use ast::edit::IndentLevel;
+use hir::HasAttrs;
 use ide_db::base_db::AnchoredPathBuf;
 use itertools::Itertools;
 use stdx::format_to;
@@ -50,9 +51,17 @@
         |builder| {
             let path = {
                 let mut buf = String::from("./");
-                match parent_module.name(ctx.db()) {
-                    Some(name) if !parent_module.is_mod_rs(ctx.db()) => {
-                        format_to!(buf, "{}/", name.display(ctx.db()))
+                let db = ctx.db();
+                match parent_module.name(db) {
+                    Some(name)
+                        if !parent_module.is_mod_rs(db)
+                            && parent_module
+                                .attrs(db)
+                                .by_key("path")
+                                .string_value_unescape()
+                                .is_none() =>
+                    {
+                        format_to!(buf, "{}/", name.display(db))
                     }
                     _ => (),
                 }
@@ -108,6 +117,72 @@
     use super::*;
 
     #[test]
+    fn extract_with_specified_path_attr() {
+        check_assist(
+            move_module_to_file,
+            r#"
+//- /main.rs
+#[path="parser/__mod.rs"]
+mod parser;
+//- /parser/__mod.rs
+fn test() {}
+mod $0expr {
+    struct A {}
+}
+"#,
+            r#"
+//- /parser/__mod.rs
+fn test() {}
+mod expr;
+//- /parser/expr.rs
+struct A {}
+"#,
+        );
+
+        check_assist(
+            move_module_to_file,
+            r#"
+//- /main.rs
+#[path="parser/a/__mod.rs"]
+mod parser;
+//- /parser/a/__mod.rs
+fn test() {}
+mod $0expr {
+    struct A {}
+}
+"#,
+            r#"
+//- /parser/a/__mod.rs
+fn test() {}
+mod expr;
+//- /parser/a/expr.rs
+struct A {}
+"#,
+        );
+
+        check_assist(
+            move_module_to_file,
+            r#"
+//- /main.rs
+#[path="a.rs"]
+mod parser;
+//- /a.rs
+fn test() {}
+mod $0expr {
+    struct A {}
+}
+"#,
+            r#"
+//- /a.rs
+fn test() {}
+mod expr;
+//- /expr.rs
+struct A {}
+"#,
+        );
+    }
+
+    #[test]
     fn extract_from_root() {
         check_assist(
             move_module_to_file,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs
index 63db606..5a197f2 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/raw_string.rs
@@ -25,7 +25,7 @@
     if token.is_raw() {
         return None;
     }
-    let value = token.value()?;
+    let value = token.value().ok()?;
     let target = token.syntax().text_range();
     acc.add(
         AssistId("make_raw_string", AssistKind::RefactorRewrite),
@@ -64,7 +64,7 @@
     if !token.is_raw() {
         return None;
     }
-    let value = token.value()?;
+    let value = token.value().ok()?;
     let target = token.syntax().text_range();
     acc.add(
         AssistId("make_usual_string", AssistKind::RefactorRewrite),
@@ -398,12 +398,12 @@
     }
 
     #[test]
-    fn remove_hash_doesnt_work() {
+    fn remove_hash_does_not_work() {
         check_assist_not_applicable(remove_hash, r#"fn f() { let s = $0"random string"; }"#);
     }
 
     #[test]
-    fn remove_hash_no_hash_doesnt_work() {
+    fn remove_hash_no_hash_does_not_work() {
         check_assist_not_applicable(remove_hash, r#"fn f() { let s = $0r"random string"; }"#);
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
index 6666966..cf135f8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
@@ -77,7 +77,7 @@
                 ast::AssocItem::MacroCall(_) => None,
             };
 
-            name.and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::max_value())
+            name.and_then(|n| ranks.get(&n.to_string()).copied()).unwrap_or(usize::MAX)
         })
         .collect();
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs
index 6310981..a48b20a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_string_with_char.rs
@@ -25,7 +25,7 @@
 // ```
 pub(crate) fn replace_string_with_char(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let token = ctx.find_token_syntax_at_offset(STRING).and_then(ast::String::cast)?;
-    let value = token.value()?;
+    let value = token.value().ok()?;
     let target = token.syntax().text_range();
 
     if value.chars().take(2).count() != 1 {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
index 0f4a8e3..d0c6ae2 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/term_search.rs
@@ -1,5 +1,5 @@
 //! Term search assist
-use hir::term_search::TermSearchCtx;
+use hir::term_search::{TermSearchConfig, TermSearchCtx};
 use ide_db::{
     assists::{AssistId, AssistKind, GroupLabel},
     famous_defs::FamousDefs,
@@ -34,7 +34,7 @@
         sema: &ctx.sema,
         scope: &scope,
         goal: target_ty,
-        config: Default::default(),
+        config: TermSearchConfig { fuel: ctx.config.term_search_fuel, ..Default::default() },
     };
     let paths = hir::term_search::term_search(&term_search_ctx);
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
index 32d6984..3b6c951 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
@@ -31,6 +31,7 @@
     prefer_no_std: false,
     prefer_prelude: true,
     assist_emit_must_use: false,
+    term_search_fuel: 400,
 };
 
 pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
@@ -46,6 +47,7 @@
     prefer_no_std: false,
     prefer_prelude: true,
     assist_emit_must_use: false,
+    term_search_fuel: 400,
 };
 
 pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
@@ -61,6 +63,7 @@
     prefer_no_std: false,
     prefer_prelude: true,
     assist_emit_must_use: false,
+    term_search_fuel: 400,
 };
 
 pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
index 802e9bc..1e31d65 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
@@ -353,7 +353,7 @@
             config: hir::term_search::TermSearchConfig {
                 enable_borrowcheck: false,
                 many_alternatives_threshold: 1,
-                depth: 6,
+                fuel: 200,
             },
         };
         let exprs = hir::term_search::term_search(&term_search_ctx);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
index 3bc329e..bf6747d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
@@ -296,7 +296,7 @@
     position: SyntaxNode,
     potential_import_name: String,
 ) -> Option<()> {
-    let _p = tracing::span!(tracing::Level::INFO, "import_on_the_fly_pat", ?potential_import_name)
+    let _p = tracing::span!(tracing::Level::INFO, "import_on_the_fly_pat_", ?potential_import_name)
         .entered();
 
     ImportScope::find_insert_use_container(&position, &ctx.sema)?;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
index 04563fb..809c305 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
@@ -15,6 +15,7 @@
     pub enable_self_on_the_fly: bool,
     pub enable_private_editable: bool,
     pub enable_term_search: bool,
+    pub term_search_fuel: u64,
     pub full_function_signatures: bool,
     pub callable: Option<CallableSnippets>,
     pub snippet_cap: Option<SnippetCap>,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 8b435f4..db34bea 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -466,7 +466,7 @@
                 cov_mark::hit!(completes_if_lifetime_without_idents);
                 TextRange::at(self.original_token.text_range().start(), TextSize::from(1))
             }
-            IDENT | LIFETIME_IDENT | UNDERSCORE => self.original_token.text_range(),
+            IDENT | LIFETIME_IDENT | UNDERSCORE | INT_NUMBER => self.original_token.text_range(),
             _ if kind.is_keyword() => self.original_token.text_range(),
             _ => TextRange::empty(self.position.offset),
         }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index ca04248..7fa31e27 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -368,7 +368,7 @@
     import_to_add: Option<LocatedImport>,
     resolution: ScopeDef,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "render_resolution_pat").entered();
     use hir::ModuleDef::*;
 
     if let ScopeDef::ModuleDef(Macro(mac)) = resolution {
@@ -386,7 +386,7 @@
     import_to_add: Option<LocatedImport>,
     resolution: ScopeDef,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "render_resolution_path").entered();
     use hir::ModuleDef::*;
 
     match resolution {
@@ -494,7 +494,7 @@
     import_to_add: Option<LocatedImport>,
     resolution: ScopeDef,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_resolution").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "render_resolution_simple_").entered();
 
     let db = ctx.db();
     let ctx = ctx.import_to_add(import_to_add);
@@ -1731,6 +1731,51 @@
     }
 
     #[test]
+    fn tuple_field_detail() {
+        check(
+            r#"
+struct S(i32);
+
+fn f() -> i32 {
+    let s = S(0);
+    s.0$0
+}
+"#,
+            SymbolKind::Field,
+            expect![[r#"
+                [
+                    CompletionItem {
+                        label: "0",
+                        source_range: 56..57,
+                        delete: 56..57,
+                        insert: "0",
+                        kind: SymbolKind(
+                            Field,
+                        ),
+                        detail: "i32",
+                        relevance: CompletionRelevance {
+                            exact_name_match: false,
+                            type_match: Some(
+                                Exact,
+                            ),
+                            is_local: false,
+                            is_item_from_trait: false,
+                            is_item_from_notable_trait: false,
+                            is_name_already_imported: false,
+                            requires_import: false,
+                            is_op_method: false,
+                            is_private_editable: false,
+                            postfix_match: None,
+                            is_definite: false,
+                            function: None,
+                        },
+                    },
+                ]
+            "#]],
+        );
+    }
+
+    #[test]
     fn record_field_and_call_relevances() {
         check_relevance(
             r#"
@@ -1808,8 +1853,7 @@
                 fn baz() [type]
                 ex baz() [type]
                 ex bar() [type]
-                ex A { bar: baz() }.bar [type]
-                ex A { bar: bar() }.bar [type]
+                ex A { bar: ... }.bar [type]
                 st A []
                 fn f() []
             "#]],
@@ -1947,8 +1991,8 @@
 }
             "#,
             expect![[r#"
-                ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify]
                 ex core::ops::Deref::deref(&t) (use core::ops::Deref) [type_could_unify]
+                ex core::ops::Deref::deref(&T(S)) (use core::ops::Deref) [type_could_unify]
                 lc m [local]
                 lc t [local]
                 lc &t [type+local]
@@ -1997,8 +2041,8 @@
 }
             "#,
             expect![[r#"
-                ex core::ops::DerefMut::deref_mut(&mut T(S)) (use core::ops::DerefMut) [type_could_unify]
                 ex core::ops::DerefMut::deref_mut(&mut t) (use core::ops::DerefMut) [type_could_unify]
+                ex core::ops::DerefMut::deref_mut(&mut T(S)) (use core::ops::DerefMut) [type_could_unify]
                 lc m [local]
                 lc t [local]
                 lc &mut t [type+local]
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
index f52a5f7..9c5cb1e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
@@ -27,7 +27,7 @@
     variant: hir::Variant,
     path: Option<hir::ModPath>,
 ) -> Option<Builder> {
-    let _p = tracing::span!(tracing::Level::INFO, "render_enum_variant").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "render_variant_lit").entered();
     let db = ctx.db();
 
     let name = local_name.unwrap_or_else(|| variant.name(db));
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
index 540cfd0..8b81a95 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
@@ -27,7 +27,7 @@
     name: hir::Name,
     macro_: hir::Macro,
 ) -> Builder {
-    let _p = tracing::span!(tracing::Level::INFO, "render_macro").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "render_macro_pat").entered();
     render(ctx, false, false, false, name, macro_)
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
index 1f032c7..70e0aa4 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
@@ -80,6 +80,7 @@
     },
     snippets: Vec::new(),
     limit: None,
+    term_search_fuel: 200,
 };
 
 pub(crate) fn completion_list(ra_fixture: &str) -> String {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs
index 64a32de..62eb642 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/predicate.rs
@@ -19,7 +19,7 @@
             en Enum      Enum
             ma makro!(…) macro_rules! makro
             md module
-            st Foo<…>    Foo<'{error}, {unknown}, _>
+            st Foo<…>    Foo<{unknown}, _>
             st Record    Record
             st Tuple     Tuple
             st Unit      Unit
@@ -92,7 +92,7 @@
             en Enum      Enum
             ma makro!(…) macro_rules! makro
             md module
-            st Foo<…>    Foo<'{error}, {unknown}, _>
+            st Foo<…>    Foo<{unknown}, _>
             st Record    Record
             st Tuple     Tuple
             st Unit      Unit
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
index 66f1bff..ff38c16 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/type_pos.rs
@@ -20,8 +20,8 @@
             en Enum      Enum
             ma makro!(…) macro_rules! makro
             md module
-            sp Self      Foo<'{error}, {unknown}, _>
-            st Foo<…>    Foo<'{error}, {unknown}, _>
+            sp Self      Foo<{unknown}, _>
+            st Foo<…>    Foo<{unknown}, _>
             st Record    Record
             st Tuple     Tuple
             st Unit      Unit
@@ -45,8 +45,8 @@
             en Enum       Enum
             ma makro!(…)  macro_rules! makro
             md module
-            sp Self       Foo<'{error}, {unknown}, _>
-            st Foo<…>     Foo<'{error}, {unknown}, _>
+            sp Self       Foo<{unknown}, _>
+            st Foo<…>     Foo<{unknown}, _>
             st Record     Record
             st Tuple      Tuple
             st Unit       Unit
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index c0f0fab..634277e 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -11,8 +11,8 @@
     Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType,
     Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field,
     Function, GenericParam, HasVisibility, HirDisplay, Impl, Label, Local, Macro, Module,
-    ModuleDef, Name, PathResolution, Semantics, Static, ToolModule, Trait, TraitAlias, TupleField,
-    TypeAlias, Variant, VariantDef, Visibility,
+    ModuleDef, Name, PathResolution, Semantics, Static, StaticLifetime, ToolModule, Trait,
+    TraitAlias, TupleField, TypeAlias, Variant, VariantDef, Visibility,
 };
 use stdx::{format_to, impl_from};
 use syntax::{
@@ -39,12 +39,13 @@
     Trait(Trait),
     TraitAlias(TraitAlias),
     TypeAlias(TypeAlias),
-    BuiltinType(BuiltinType),
     SelfType(Impl),
     GenericParam(GenericParam),
     Local(Local),
     Label(Label),
     DeriveHelper(DeriveHelper),
+    BuiltinType(BuiltinType),
+    BuiltinLifetime(StaticLifetime),
     BuiltinAttr(BuiltinAttr),
     ToolModule(ToolModule),
     ExternCrateDecl(ExternCrateDecl),
@@ -83,6 +84,7 @@
             Definition::DeriveHelper(it) => it.derive().module(db),
             Definition::BuiltinAttr(_)
             | Definition::BuiltinType(_)
+            | Definition::BuiltinLifetime(_)
             | Definition::TupleField(_)
             | Definition::ToolModule(_) => return None,
         };
@@ -112,6 +114,7 @@
             Definition::BuiltinType(_) | Definition::TupleField(_) => Visibility::Public,
             Definition::Macro(_) => return None,
             Definition::BuiltinAttr(_)
+            | Definition::BuiltinLifetime(_)
             | Definition::ToolModule(_)
             | Definition::SelfType(_)
             | Definition::Local(_)
@@ -141,6 +144,7 @@
             Definition::Local(it) => it.name(db),
             Definition::GenericParam(it) => it.name(db),
             Definition::Label(it) => it.name(db),
+            Definition::BuiltinLifetime(StaticLifetime) => hir::known::STATIC_LIFETIME,
             Definition::BuiltinAttr(_) => return None, // FIXME
             Definition::ToolModule(_) => return None,  // FIXME
             Definition::DeriveHelper(it) => it.name(db),
@@ -174,6 +178,7 @@
                     doc_owner.docs(fd.0.db)
                 })
             }
+            Definition::BuiltinLifetime(StaticLifetime) => None,
             Definition::Local(_) => None,
             Definition::SelfType(impl_def) => {
                 impl_def.self_ty(db).as_adt().map(|adt| adt.docs(db))?
@@ -228,6 +233,7 @@
             Definition::TraitAlias(it) => it.display(db).to_string(),
             Definition::TypeAlias(it) => it.display(db).to_string(),
             Definition::BuiltinType(it) => it.name().display(db).to_string(),
+            Definition::BuiltinLifetime(it) => it.name().display(db).to_string(),
             Definition::Local(it) => {
                 let ty = it.ty(db);
                 let ty_display = ty.display_truncated(db, None);
@@ -693,6 +699,9 @@
     ) -> Option<NameRefClass> {
         let _p = tracing::span!(tracing::Level::INFO, "NameRefClass::classify_lifetime", ?lifetime)
             .entered();
+        if lifetime.text() == "'static" {
+            return Some(NameRefClass::Definition(Definition::BuiltinLifetime(StaticLifetime)));
+        }
         let parent = lifetime.syntax().parent()?;
         match parent.kind() {
             SyntaxKind::BREAK_EXPR | SyntaxKind::CONTINUE_EXPR => {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
index c597555..766bfcf 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
@@ -209,8 +209,7 @@
         prefer_no_std: bool,
         prefer_prelude: bool,
     ) -> impl Iterator<Item = LocatedImport> {
-        let _p =
-            tracing::span!(tracing::Level::INFO, "import_assets::search_for_imports").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for_imports").entered();
         self.search_for(sema, Some(prefix_kind), prefer_no_std, prefer_prelude)
     }
 
@@ -221,7 +220,7 @@
         prefer_no_std: bool,
         prefer_prelude: bool,
     ) -> impl Iterator<Item = LocatedImport> {
-        let _p = tracing::span!(tracing::Level::INFO, "import_assets::search_for_relative_paths")
+        let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for_relative_paths")
             .entered();
         self.search_for(sema, None, prefer_no_std, prefer_prelude)
     }
@@ -263,7 +262,7 @@
         prefer_no_std: bool,
         prefer_prelude: bool,
     ) -> impl Iterator<Item = LocatedImport> {
-        let _p = tracing::span!(tracing::Level::INFO, "import_assets::search_for").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::search_for").entered();
 
         let scope = match sema.scope(&self.candidate_node) {
             Some(it) => it,
@@ -308,7 +307,7 @@
     }
 
     fn scope_definitions(&self, sema: &Semantics<'_, RootDatabase>) -> FxHashSet<ScopeDef> {
-        let _p = tracing::span!(tracing::Level::INFO, "import_assets::scope_definitions").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::scope_definitions").entered();
         let mut scope_definitions = FxHashSet::default();
         if let Some(scope) = sema.scope(&self.candidate_node) {
             scope.process_all_names(&mut |_, scope_def| {
@@ -327,7 +326,7 @@
     scope_filter: impl Fn(ItemInNs) -> bool + Copy,
 ) -> FxHashSet<LocatedImport> {
     let _p =
-        tracing::span!(tracing::Level::INFO, "import_assets::path_applicable_imports").entered();
+        tracing::span!(tracing::Level::INFO, "ImportAssets::path_applicable_imports").entered();
 
     match &path_candidate.qualifier {
         None => {
@@ -374,7 +373,7 @@
     original_item: ItemInNs,
     scope_filter: impl Fn(ItemInNs) -> bool,
 ) -> Option<LocatedImport> {
-    let _p = tracing::span!(tracing::Level::INFO, "import_assets::import_for_item").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::import_for_item").entered();
     let [first_segment, ..] = unresolved_qualifier else { return None };
 
     let item_as_assoc = item_as_assoc(db, original_item);
@@ -508,8 +507,7 @@
     mod_path: impl Fn(ItemInNs) -> Option<ModPath>,
     scope_filter: impl Fn(hir::Trait) -> bool,
 ) -> FxHashSet<LocatedImport> {
-    let _p =
-        tracing::span!(tracing::Level::INFO, "import_assets::trait_applicable_items").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "ImportAssets::trait_applicable_items").entered();
 
     let db = sema.db;
 
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
index e97f1b8..026d4e36 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
@@ -194,7 +194,7 @@
     cfg: &InsertUseConfig,
     alias: Option<ast::Rename>,
 ) {
-    let _p = tracing::span!(tracing::Level::INFO, "insert_use").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "insert_use_with_alias_option").entered();
     let mut mb = match cfg.granularity {
         ImportGranularity::Crate => Some(MergeBehavior::Crate),
         ImportGranularity::Module => Some(MergeBehavior::Module),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
index 024e8f6..58077f6 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
@@ -1,6 +1,6 @@
 //! rust-analyzer is lazy and doesn't compute anything unless asked. This
 //! sometimes is counter productive when, for example, the first goto definition
-//! request takes longer to compute. This modules implemented prepopulation of
+//! request takes longer to compute. This module implements prepopulation of
 //! various caches, it's not really advanced at the moment.
 mod topologic_sort;
 
@@ -32,7 +32,7 @@
     num_worker_threads: u8,
     cb: &(dyn Fn(ParallelPrimeCachesProgress) + Sync),
 ) {
-    let _p = tracing::span!(tracing::Level::INFO, "prime_caches").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "parallel_prime_caches").entered();
 
     let graph = db.crate_graph();
     let mut crates_to_prime = {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index 6a70429..288d56b 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -196,11 +196,12 @@
                         .and_then(syn_ctx_is_root)
                 }
             }
-            Definition::BuiltinType(_) => return None,
-            Definition::SelfType(_) => return None,
-            Definition::BuiltinAttr(_) => return None,
-            Definition::ToolModule(_) => return None,
-            Definition::TupleField(_) => return None,
+            Definition::BuiltinType(_)
+            | Definition::BuiltinLifetime(_)
+            | Definition::BuiltinAttr(_)
+            | Definition::SelfType(_)
+            | Definition::ToolModule(_)
+            | Definition::TupleField(_) => return None,
             // FIXME: This should be doable in theory
             Definition::DeriveHelper(_) => return None,
         };
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index cb10331..8f63306 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -1,7 +1,7 @@
 //! Implementation of find-usages functionality.
 //!
 //! It is based on the standard ide trick: first, we run a fast text search to
-//! get a super-set of matches. Then, we we confirm each match using precise
+//! get a super-set of matches. Then, we confirm each match using precise
 //! name resolution.
 
 use std::mem;
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index c65467a..12085f9 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -301,8 +301,8 @@
     }
 
     fn range_to_map_value(start: usize, end: usize) -> u64 {
-        debug_assert![start <= (std::u32::MAX as usize)];
-        debug_assert![end <= (std::u32::MAX as usize)];
+        debug_assert![start <= (u32::MAX as usize)];
+        debug_assert![end <= (u32::MAX as usize)];
 
         ((start as u64) << 32) | end as u64
     }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index 241fddb..b3dde97 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -7,7 +7,7 @@
     helpers::mod_path_to_ast,
     imports::insert_use::{insert_use, ImportScope},
     source_change::SourceChangeBuilder,
-    RootDatabase,
+    FxHashMap, RootDatabase,
 };
 use itertools::Itertools;
 use stdx::{format_to, never};
@@ -22,15 +22,22 @@
 #[derive(Default)]
 struct State {
     result: String,
-    struct_counts: usize,
     has_serialize: bool,
     has_deserialize: bool,
+    names: FxHashMap<String, usize>,
 }
 
 impl State {
-    fn generate_new_name(&mut self) -> ast::Name {
-        self.struct_counts += 1;
-        make::name(&format!("Struct{}", self.struct_counts))
+    fn generate_new_name(&mut self, name: &str) -> ast::Name {
+        let name = stdx::to_camel_case(name);
+        let count = if let Some(count) = self.names.get_mut(&name) {
+            *count += 1;
+            *count
+        } else {
+            self.names.insert(name.clone(), 1);
+            1
+        };
+        make::name(&format!("{}{}", name, count))
     }
 
     fn serde_derive(&self) -> String {
@@ -52,15 +59,21 @@
         }
     }
 
-    fn build_struct(&mut self, value: &serde_json::Map<String, serde_json::Value>) -> ast::Type {
-        let name = self.generate_new_name();
+    fn build_struct(
+        &mut self,
+        name: &str,
+        value: &serde_json::Map<String, serde_json::Value>,
+    ) -> ast::Type {
+        let name = self.generate_new_name(name);
         let ty = make::ty(&name.to_string());
         let strukt = make::struct_(
             None,
             name,
             None,
             make::record_field_list(value.iter().sorted_unstable_by_key(|x| x.0).map(
-                |(name, value)| make::record_field(None, make::name(name), self.type_of(value)),
+                |(name, value)| {
+                    make::record_field(None, make::name(name), self.type_of(name, value))
+                },
             ))
             .into(),
         );
@@ -68,7 +81,7 @@
         ty
     }
 
-    fn type_of(&mut self, value: &serde_json::Value) -> ast::Type {
+    fn type_of(&mut self, name: &str, value: &serde_json::Value) -> ast::Type {
         match value {
             serde_json::Value::Null => make::ty_unit(),
             serde_json::Value::Bool(_) => make::ty("bool"),
@@ -76,12 +89,12 @@
             serde_json::Value::String(_) => make::ty("String"),
             serde_json::Value::Array(it) => {
                 let ty = match it.iter().next() {
-                    Some(x) => self.type_of(x),
+                    Some(x) => self.type_of(name, x),
                     None => make::ty_placeholder(),
                 };
                 make::ty(&format!("Vec<{ty}>"))
             }
-            serde_json::Value::Object(x) => self.build_struct(x),
+            serde_json::Value::Object(x) => self.build_struct(name, x),
         }
     }
 }
@@ -113,7 +126,7 @@
                 let serialize_resolved = scope_resolve("::serde::Serialize");
                 state.has_deserialize = deserialize_resolved.is_some();
                 state.has_serialize = serialize_resolved.is_some();
-                state.build_struct(&it);
+                state.build_struct("Root", &it);
                 edit.insert(range.start(), state.result);
                 acc.push(
                     Diagnostic::new(
@@ -218,7 +231,7 @@
             }
 
             #[derive(Serialize)]
-            struct Struct1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String }
+            struct Root1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String }
 
             "#,
         );
@@ -237,9 +250,44 @@
             }
             "#,
             r#"
-            struct Struct3{  }
-            struct Struct2{ kind: String, value: Struct3 }
-            struct Struct1{ bar: Struct2, foo: String }
+            struct Value1{  }
+            struct Bar1{ kind: String, value: Value1 }
+            struct Root1{ bar: Bar1, foo: String }
+
+            "#,
+        );
+    }
+
+    #[test]
+    fn naming() {
+        check_fix(
+            r#"
+            {$0
+                "user": {
+                    "address": {
+                        "street": "Main St",
+                        "house": 3
+                    },
+                    "email": "example@example.com"
+                },
+                "another_user": {
+                    "user": {
+                        "address": {
+                            "street": "Main St",
+                            "house": 3
+                        },
+                        "email": "example@example.com"
+                    }
+                }
+            }
+            "#,
+            r#"
+            struct Address1{ house: i64, street: String }
+            struct User1{ address: Address1, email: String }
+            struct AnotherUser1{ user: User1 }
+            struct Address2{ house: i64, street: String }
+            struct User2{ address: Address2, email: String }
+            struct Root1{ another_user: AnotherUser1, user: User2 }
 
             "#,
         );
@@ -276,9 +324,9 @@
             use serde::Deserialize;
 
             #[derive(Serialize, Deserialize)]
-            struct Struct2{ x: i64, y: i64 }
+            struct OfObject1{ x: i64, y: i64 }
             #[derive(Serialize, Deserialize)]
-            struct Struct1{ empty: Vec<_>, nested: Vec<Vec<Vec<i64>>>, of_object: Vec<Struct2>, of_string: Vec<String> }
+            struct Root1{ empty: Vec<_>, nested: Vec<Vec<Vec<i64>>>, of_object: Vec<OfObject1>, of_string: Vec<String> }
 
             "#,
         );
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index 8d77e56..5a32064 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -1,5 +1,5 @@
 use either::Either;
-use hir::{db::ExpandDatabase, HasSource, HirDisplay, HirFileIdExt, Semantics};
+use hir::{db::ExpandDatabase, HasSource, HirDisplay, HirFileIdExt, Semantics, VariantId};
 use ide_db::{base_db::FileId, source_change::SourceChange, RootDatabase};
 use syntax::{
     ast::{self, edit::IndentLevel, make},
@@ -25,7 +25,10 @@
     } else {
         Diagnostic::new_with_syntax_node_ptr(
             ctx,
-            DiagnosticCode::RustcHardError("E0559"),
+            match d.variant {
+                VariantId::EnumVariantId(_) => DiagnosticCode::RustcHardError("E0559"),
+                _ => DiagnosticCode::RustcHardError("E0560"),
+            },
             "no such field",
             node,
         )
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index 56c8181..656d79d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -1,6 +1,6 @@
 use hir::{
     db::ExpandDatabase,
-    term_search::{term_search, TermSearchCtx},
+    term_search::{term_search, TermSearchConfig, TermSearchCtx},
     ClosureStyle, HirDisplay,
 };
 use ide_db::{
@@ -47,7 +47,7 @@
         sema: &ctx.sema,
         scope: &scope,
         goal: d.expected.clone(),
-        config: Default::default(),
+        config: TermSearchConfig { fuel: ctx.config.term_search_fuel, ..Default::default() },
     };
     let paths = term_search(&term_search_ctx);
 
@@ -274,7 +274,7 @@
 }
 fn asd() -> Bar {
     let a = Baz;
-    Foo::foo(a)
+    Foo::foo(_)
 }
 ",
         );
@@ -363,7 +363,7 @@
 }
 fn main() {
     let a = A;
-    let c: Bar = Foo::foo(&a);
+    let c: Bar = Foo::foo(_);
 }"#,
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index c3ced36..15543a5 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -232,6 +232,7 @@
     pub insert_use: InsertUseConfig,
     pub prefer_no_std: bool,
     pub prefer_prelude: bool,
+    pub term_search_fuel: u64,
 }
 
 impl DiagnosticsConfig {
@@ -256,6 +257,7 @@
             },
             prefer_no_std: false,
             prefer_prelude: true,
+            term_search_fuel: 400,
         }
     }
 }
@@ -297,11 +299,10 @@
 ) -> Vec<Diagnostic> {
     let _p = tracing::span!(tracing::Level::INFO, "diagnostics").entered();
     let sema = Semantics::new(db);
-    let parse = db.parse(file_id);
     let mut res = Vec::new();
 
     // [#34344] Only take first 128 errors to prevent slowing down editor/ide, the number 128 is chosen arbitrarily.
-    res.extend(parse.errors().into_iter().take(128).map(|err| {
+    res.extend(db.parse_errors(file_id).as_deref().into_iter().flatten().take(128).map(|err| {
         Diagnostic::new(
             DiagnosticCode::RustcHardError("syntax-error"),
             format!("Syntax Error: {err}"),
@@ -340,7 +341,8 @@
             AnyDiagnostic::MacroDefError(d) => handlers::macro_error::macro_def_error(&ctx, &d),
             AnyDiagnostic::MacroError(d) => handlers::macro_error::macro_error(&ctx, &d),
             AnyDiagnostic::MacroExpansionParseError(d) => {
-                res.extend(d.errors.iter().take(32).map(|err| {
+                // FIXME: Point to the correct error span here, not just the macro-call name
+                res.extend(d.errors.iter().take(16).map(|err| {
                     {
                         Diagnostic::new(
                             DiagnosticCode::RustcHardError("syntax-error"),
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
index bb5c2b7..cd5e95c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
@@ -293,6 +293,7 @@
         // This should be ignored since we conditionally remove code which creates single item use with braces
         config.disabled.insert("unused_braces".to_owned());
         config.disabled.insert("unused_variables".to_owned());
+        config.disabled.insert("remove-unnecessary-else".to_owned());
         check_diagnostics_with_config(config, &source);
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index 64b4ccc..8d765df 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -214,8 +214,9 @@
         Definition::SelfType(it) => it.resolve_doc_path(db, link, ns),
         Definition::ExternCrateDecl(it) => it.resolve_doc_path(db, link, ns),
         Definition::BuiltinAttr(_)
-        | Definition::ToolModule(_)
         | Definition::BuiltinType(_)
+        | Definition::BuiltinLifetime(_)
+        | Definition::ToolModule(_)
         | Definition::TupleField(_)
         | Definition::Local(_)
         | Definition::GenericParam(_)
@@ -648,6 +649,7 @@
         | Definition::TupleField(_)
         | Definition::Label(_)
         | Definition::BuiltinAttr(_)
+        | Definition::BuiltinLifetime(_)
         | Definition::ToolModule(_)
         | Definition::DeriveHelper(_) => return None,
     };
diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
index e2d629a..1ead045 100644
--- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
@@ -76,8 +76,6 @@
         return derive;
     }
 
-    // FIXME: Intermix attribute and bang! expansions
-    // currently we only recursively expand one of the two types
     let mut anc = tok.parent_ancestors();
     let (name, expanded, kind) = loop {
         let node = anc.next()?;
@@ -86,7 +84,7 @@
             if let Some(def) = sema.resolve_attr_macro_call(&item) {
                 break (
                     def.name(db).display(db).to_string(),
-                    expand_attr_macro_recur(&sema, &item)?,
+                    expand_macro_recur(&sema, &item)?,
                     SyntaxKind::MACRO_ITEMS,
                 );
             }
@@ -94,11 +92,9 @@
         if let Some(mac) = ast::MacroCall::cast(node) {
             let mut name = mac.path()?.segment()?.name_ref()?.to_string();
             name.push('!');
-            break (
-                name,
-                expand_macro_recur(&sema, &mac)?,
-                mac.syntax().parent().map(|it| it.kind()).unwrap_or(SyntaxKind::MACRO_ITEMS),
-            );
+            let syntax_kind =
+                mac.syntax().parent().map(|it| it.kind()).unwrap_or(SyntaxKind::MACRO_ITEMS);
+            break (name, expand_macro_recur(&sema, &ast::Item::MacroCall(mac))?, syntax_kind);
         }
     };
 
@@ -112,31 +108,23 @@
 
 fn expand_macro_recur(
     sema: &Semantics<'_, RootDatabase>,
-    macro_call: &ast::MacroCall,
+    macro_call: &ast::Item,
 ) -> Option<SyntaxNode> {
-    let expanded = sema.expand(macro_call)?.clone_for_update();
-    expand(sema, expanded, ast::MacroCall::cast, expand_macro_recur)
+    let expanded = match macro_call {
+        item @ ast::Item::MacroCall(macro_call) => {
+            sema.expand_attr_macro(item).or_else(|| sema.expand(macro_call))?.clone_for_update()
+        }
+        item => sema.expand_attr_macro(item)?.clone_for_update(),
+    };
+    expand(sema, expanded)
 }
 
-fn expand_attr_macro_recur(
-    sema: &Semantics<'_, RootDatabase>,
-    item: &ast::Item,
-) -> Option<SyntaxNode> {
-    let expanded = sema.expand_attr_macro(item)?.clone_for_update();
-    expand(sema, expanded, ast::Item::cast, expand_attr_macro_recur)
-}
-
-fn expand<T: AstNode>(
-    sema: &Semantics<'_, RootDatabase>,
-    expanded: SyntaxNode,
-    f: impl FnMut(SyntaxNode) -> Option<T>,
-    exp: impl Fn(&Semantics<'_, RootDatabase>, &T) -> Option<SyntaxNode>,
-) -> Option<SyntaxNode> {
-    let children = expanded.descendants().filter_map(f);
+fn expand(sema: &Semantics<'_, RootDatabase>, expanded: SyntaxNode) -> Option<SyntaxNode> {
+    let children = expanded.descendants().filter_map(ast::Item::cast);
     let mut replacements = Vec::new();
 
     for child in children {
-        if let Some(new_node) = exp(sema, &child) {
+        if let Some(new_node) = expand_macro_recur(sema, &child) {
             // check if the whole original syntax is replaced
             if expanded == *child.syntax() {
                 return Some(new_node);
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index ddeeca5..76b80fc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -123,7 +123,7 @@
     {
         return None;
     }
-    let path = token.value()?;
+    let path = token.value().ok()?;
 
     let file_id = sema.db.resolve_path(AnchoredPath { anchor: file_id, path: &path })?;
     let size = sema.db.file_text(file_id).len().try_into().ok()?;
@@ -179,11 +179,11 @@
         AssocItem::Const(..) | AssocItem::TypeAlias(..) => {
             let trait_ = assoc.implemented_trait(db)?;
             let name = def.name(db)?;
-            let discri_value = discriminant(&assoc);
+            let discriminant_value = discriminant(&assoc);
             trait_
                 .items(db)
                 .iter()
-                .filter(|itm| discriminant(*itm) == discri_value)
+                .filter(|itm| discriminant(*itm) == discriminant_value)
                 .find_map(|itm| (itm.name(db)? == name).then(|| itm.try_to_nav(db)).flatten())
                 .map(|it| it.collect())
         }
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 95de3c8..bdb5608 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -15,7 +15,7 @@
     FxIndexSet, RootDatabase,
 };
 use itertools::{multizip, Itertools};
-use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, T};
+use syntax::{ast, AstNode, SyntaxKind::*, SyntaxNode, T};
 
 use crate::{
     doc_links::token_as_doc_comment,
@@ -33,7 +33,8 @@
     pub keywords: bool,
     pub format: HoverDocFormat,
     pub max_trait_assoc_items_count: Option<usize>,
-    pub max_struct_field_count: Option<usize>,
+    pub max_fields_count: Option<usize>,
+    pub max_enum_variants_count: Option<usize>,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@@ -297,61 +298,8 @@
         })
         // tokens
         .or_else(|| {
-            let mut res = HoverResult::default();
-            match_ast! {
-                match original_token {
-                    ast::String(string) => {
-                        res.markup = Markup::fenced_block_text(format_args!("{}", string.value()?));
-                    },
-                    ast::ByteString(string) => {
-                        res.markup = Markup::fenced_block_text(format_args!("{:?}", string.value()?));
-                    },
-                    ast::CString(string) => {
-                        let val = string.value()?;
-                        res.markup = Markup::fenced_block_text(format_args!("{}", std::str::from_utf8(val.as_ref()).ok()?));
-                    },
-                    ast::Char(char) => {
-                        let mut res = HoverResult::default();
-                        res.markup = Markup::fenced_block_text(format_args!("{}", char.value()?));
-                    },
-                    ast::Byte(byte) => {
-                        res.markup = Markup::fenced_block_text(format_args!("0x{:X}", byte.value()?));
-                    },
-                    ast::FloatNumber(num) => {
-                        res.markup = if num.suffix() == Some("f32") {
-                            match num.value_f32() {
-                                Ok(num) => {
-                                    Markup::fenced_block_text(format_args!("{num} (bits: 0x{:X})", num.to_bits()))
-                                },
-                                Err(e) => {
-                                    Markup::fenced_block_text(format_args!("{e}"))
-                                },
-                            }
-                        } else {
-                            match num.value() {
-                                Ok(num) => {
-                                    Markup::fenced_block_text(format_args!("{num} (bits: 0x{:X})", num.to_bits()))
-                                },
-                                Err(e) => {
-                                    Markup::fenced_block_text(format_args!("{e}"))
-                                },
-                            }
-                        };
-                    },
-                    ast::IntNumber(num) => {
-                        res.markup = match num.value() {
-                            Ok(num) => {
-                                Markup::fenced_block_text(format_args!("{num} (0x{num:X}|0b{num:b})"))
-                            },
-                            Err(e) => {
-                                Markup::fenced_block_text(format_args!("{e}"))
-                            },
-                        };
-                    },
-                    _ => return None
-                }
-            }
-            Some(res)
+            render::literal(sema, original_token.clone())
+                .map(|markup| HoverResult { markup, actions: vec![] })
         });
 
     result.map(|mut res: HoverResult| {
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index 3f0fc85..3bc17f9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -17,11 +17,7 @@
 };
 use itertools::Itertools;
 use stdx::format_to;
-use syntax::{
-    algo,
-    ast::{self, RecordPat},
-    match_ast, AstNode, Direction, SyntaxToken, T,
-};
+use syntax::{algo, ast, match_ast, AstNode, AstToken, Direction, SyntaxToken, T};
 
 use crate::{
     doc_links::{remove_links, rewrite_links},
@@ -276,7 +272,7 @@
 pub(super) fn struct_rest_pat(
     sema: &Semantics<'_, RootDatabase>,
     _config: &HoverConfig,
-    pattern: &RecordPat,
+    pattern: &ast::RecordPat,
 ) -> HoverResult {
     let missing_fields = sema.record_pattern_missing_fields(pattern);
 
@@ -411,8 +407,21 @@
         Definition::Trait(trait_) => {
             trait_.display_limited(db, config.max_trait_assoc_items_count).to_string()
         }
-        Definition::Adt(Adt::Struct(struct_)) => {
-            struct_.display_limited(db, config.max_struct_field_count).to_string()
+        Definition::Adt(adt @ (Adt::Struct(_) | Adt::Union(_))) => {
+            adt.display_limited(db, config.max_fields_count).to_string()
+        }
+        Definition::Variant(variant) => {
+            variant.display_limited(db, config.max_fields_count).to_string()
+        }
+        Definition::Adt(adt @ Adt::Enum(_)) => {
+            adt.display_limited(db, config.max_enum_variants_count).to_string()
+        }
+        Definition::SelfType(impl_def) => {
+            let self_ty = &impl_def.self_ty(db);
+            match self_ty.as_adt() {
+                Some(adt) => adt.display_limited(db, config.max_fields_count).to_string(),
+                None => self_ty.display(db).to_string(),
+            }
         }
         Definition::Macro(it) => {
             let mut label = it.display(db).to_string();
@@ -513,6 +522,60 @@
     markup(docs.map(Into::into), desc, mod_path)
 }
 
+pub(super) fn literal(sema: &Semantics<'_, RootDatabase>, token: SyntaxToken) -> Option<Markup> {
+    let lit = token.parent().and_then(ast::Literal::cast)?;
+    let ty = if let Some(p) = lit.syntax().parent().and_then(ast::Pat::cast) {
+        sema.type_of_pat(&p)?
+    } else {
+        sema.type_of_expr(&ast::Expr::Literal(lit))?
+    }
+    .original;
+
+    let value = match_ast! {
+        match token {
+            ast::String(string)     => string.value().as_ref().map_err(|e| format!("{e:?}")).map(ToString::to_string),
+            ast::ByteString(string) => string.value().as_ref().map_err(|e| format!("{e:?}")).map(|it| format!("{it:?}")),
+            ast::CString(string)    => string.value().as_ref().map_err(|e| format!("{e:?}")).map(|it| std::str::from_utf8(it).map_or_else(|e| format!("{e:?}"), ToOwned::to_owned)),
+            ast::Char(char)         => char  .value().as_ref().map_err(|e| format!("{e:?}")).map(ToString::to_string),
+            ast::Byte(byte)         => byte  .value().as_ref().map_err(|e| format!("{e:?}")).map(|it| format!("0x{it:X}")),
+            ast::FloatNumber(num) => {
+                let (text, _) = num.split_into_parts();
+                let text = text.replace('_', "");
+                if ty.as_builtin().map(|it| it.is_f32()).unwrap_or(false) {
+                    match text.parse::<f32>() {
+                        Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())),
+                        Err(e) => Err(e.to_string()),
+                    }
+                } else {
+                    match text.parse::<f64>() {
+                        Ok(num) => Ok(format!("{num} (bits: 0x{:X})", num.to_bits())),
+                        Err(e) => Err(e.to_string()),
+                    }
+                }
+            },
+            ast::IntNumber(num) => match num.value() {
+                Ok(num) => Ok(format!("{num} (0x{num:X}|0b{num:b})")),
+                Err(e) => Err(e.to_string()),
+            },
+            _ => return None
+        }
+    };
+    let ty = ty.display(sema.db);
+
+    let mut s = format!("```rust\n{ty}\n```\n___\n\n");
+    match value {
+        Ok(value) => {
+            if let Some(newline) = value.find('\n') {
+                format_to!(s, "value of literal (truncated up to newline): {}", &value[..newline])
+            } else {
+                format_to!(s, "value of literal: {value}")
+            }
+        }
+        Err(error) => format_to!(s, "invalid literal: {error}"),
+    }
+    Some(s.into())
+}
+
 fn render_notable_trait_comment(
     db: &RootDatabase,
     notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
@@ -693,15 +756,7 @@
 }
 
 fn definition_mod_path(db: &RootDatabase, def: &Definition) -> Option<String> {
-    if matches!(
-        def,
-        Definition::GenericParam(_)
-            | Definition::BuiltinType(_)
-            | Definition::Local(_)
-            | Definition::Label(_)
-            | Definition::BuiltinAttr(_)
-            | Definition::ToolModule(_)
-    ) {
+    if matches!(def, Definition::GenericParam(_) | Definition::Local(_) | Definition::Label(_)) {
         return None;
     }
     def.module(db).map(|module| path(db, module, definition_owner_name(db, def)))
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 6bbc8b3..20d07bf 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -18,7 +18,8 @@
     format: HoverDocFormat::Markdown,
     keywords: true,
     max_trait_assoc_items_count: None,
-    max_struct_field_count: None,
+    max_fields_count: Some(5),
+    max_enum_variants_count: Some(5),
 };
 
 fn check_hover_no_result(ra_fixture: &str) {
@@ -51,13 +52,43 @@
 }
 
 #[track_caller]
-fn check_hover_struct_limit(count: usize, ra_fixture: &str, expect: Expect) {
+fn check_hover_fields_limit(
+    fields_count: impl Into<Option<usize>>,
+    ra_fixture: &str,
+    expect: Expect,
+) {
     let (analysis, position) = fixture::position(ra_fixture);
     let hover = analysis
         .hover(
             &HoverConfig {
                 links_in_hover: true,
-                max_struct_field_count: Some(count),
+                max_fields_count: fields_count.into(),
+                ..HOVER_BASE_CONFIG
+            },
+            FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
+        )
+        .unwrap()
+        .unwrap();
+
+    let content = analysis.db.file_text(position.file_id);
+    let hovered_element = &content[hover.range];
+
+    let actual = format!("*{hovered_element}*\n{}\n", hover.info.markup);
+    expect.assert_eq(&actual)
+}
+
+#[track_caller]
+fn check_hover_enum_variants_limit(
+    variants_count: impl Into<Option<usize>>,
+    ra_fixture: &str,
+    expect: Expect,
+) {
+    let (analysis, position) = fixture::position(ra_fixture);
+    let hover = analysis
+        .hover(
+            &HoverConfig {
+                links_in_hover: true,
+                max_enum_variants_count: variants_count.into(),
                 ..HOVER_BASE_CONFIG
             },
             FileRange { file_id: position.file_id, range: TextRange::empty(position.offset) },
@@ -876,7 +907,9 @@
 
             ```rust
             // size = 4, align = 4
-            struct Foo
+            struct Foo {
+                field: u32,
+            }
             ```
         "#]],
     );
@@ -896,6 +929,9 @@
             struct Foo
             where
                 u32: Copy,
+            {
+                field: u32,
+            }
             ```
         "#]],
     );
@@ -903,7 +939,7 @@
 
 #[test]
 fn hover_record_struct_limit() {
-    check_hover_struct_limit(
+    check_hover_fields_limit(
         3,
         r#"
     struct Foo$0 { a: u32, b: i32, c: i32 }
@@ -917,7 +953,7 @@
 
             ```rust
             // size = 12 (0xC), align = 4
-            struct Foo  {
+            struct Foo {
                 a: u32,
                 b: i32,
                 c: i32,
@@ -925,7 +961,7 @@
             ```
         "#]],
     );
-    check_hover_struct_limit(
+    check_hover_fields_limit(
         3,
         r#"
     struct Foo$0 { a: u32 }
@@ -939,13 +975,13 @@
 
             ```rust
             // size = 4, align = 4
-            struct Foo  {
+            struct Foo {
                 a: u32,
             }
             ```
         "#]],
     );
-    check_hover_struct_limit(
+    check_hover_fields_limit(
         3,
         r#"
     struct Foo$0 { a: u32, b: i32, c: i32, d: u32 }
@@ -959,7 +995,7 @@
 
             ```rust
             // size = 16 (0x10), align = 4
-            struct Foo  {
+            struct Foo {
                 a: u32,
                 b: i32,
                 c: i32,
@@ -968,6 +1004,338 @@
             ```
         "#]],
     );
+    check_hover_fields_limit(
+        None,
+        r#"
+    struct Foo$0 { a: u32, b: i32, c: i32 }
+    "#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 12 (0xC), align = 4
+            struct Foo
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        0,
+        r#"
+    struct Foo$0 { a: u32, b: i32, c: i32 }
+    "#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 12 (0xC), align = 4
+            struct Foo { /* … */ }
+            ```
+        "#]],
+    );
+
+    // No extra spaces within `{}` when there are no fields
+    check_hover_fields_limit(
+        5,
+        r#"
+    struct Foo$0 {}
+    "#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 0, align = 1
+            struct Foo {}
+            ```
+        "#]],
+    );
+}
+
+#[test]
+fn hover_record_variant_limit() {
+    check_hover_fields_limit(
+        3,
+        r#"
+    enum Foo { A$0 { a: u32, b: i32, c: i32 } }
+    "#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            test::Foo
+            ```
+
+            ```rust
+            // size = 12 (0xC), align = 4
+            A { a: u32, b: i32, c: i32, }
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        3,
+        r#"
+    enum Foo { A$0 { a: u32 } }
+    "#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            test::Foo
+            ```
+
+            ```rust
+            // size = 4, align = 4
+            A { a: u32, }
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        3,
+        r#"
+    enum Foo { A$0 { a: u32, b: i32, c: i32, d: u32 } }
+    "#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            test::Foo
+            ```
+
+            ```rust
+            // size = 16 (0x10), align = 4
+            A { a: u32, b: i32, c: i32, /* … */ }
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        None,
+        r#"
+    enum Foo { A$0 { a: u32, b: i32, c: i32 } }
+    "#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            test::Foo
+            ```
+
+            ```rust
+            // size = 12 (0xC), align = 4
+            A
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        0,
+        r#"
+    enum Foo { A$0 { a: u32, b: i32, c: i32 } }
+    "#,
+        expect![[r#"
+            *A*
+
+            ```rust
+            test::Foo
+            ```
+
+            ```rust
+            // size = 12 (0xC), align = 4
+            A { /* … */ }
+            ```
+        "#]],
+    );
+}
+
+#[test]
+fn hover_enum_limit() {
+    check_hover_enum_variants_limit(
+        5,
+        r#"enum Foo$0 { A, B }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 1, align = 1, niches = 254
+            enum Foo {
+                A,
+                B,
+            }
+            ```
+        "#]],
+    );
+    check_hover_enum_variants_limit(
+        1,
+        r#"enum Foo$0 { A, B }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 1, align = 1, niches = 254
+            enum Foo {
+                A,
+                /* … */
+            }
+            ```
+        "#]],
+    );
+    check_hover_enum_variants_limit(
+        0,
+        r#"enum Foo$0 { A, B }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 1, align = 1, niches = 254
+            enum Foo { /* … */ }
+            ```
+        "#]],
+    );
+    check_hover_enum_variants_limit(
+        None,
+        r#"enum Foo$0 { A, B }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 1, align = 1, niches = 254
+            enum Foo
+            ```
+        "#]],
+    );
+    check_hover_enum_variants_limit(
+        7,
+        r#"enum Enum$0 {
+               Variant {},
+               Variant2 { field: i32 },
+               Variant3 { field: i32, field2: i32 },
+               Variant4(),
+               Variant5(i32),
+               Variant6(i32, i32),
+               Variant7,
+               Variant8,
+           }"#,
+        expect![[r#"
+            *Enum*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 12 (0xC), align = 4, niches = 4294967288
+            enum Enum {
+                Variant {},
+                Variant2 { /* … */ },
+                Variant3 { /* … */ },
+                Variant4(),
+                Variant5( /* … */ ),
+                Variant6( /* … */ ),
+                Variant7,
+                /* … */
+            }
+            ```
+        "#]],
+    );
+}
+
+#[test]
+fn hover_union_limit() {
+    check_hover_fields_limit(
+        5,
+        r#"union Foo$0 { a: u32, b: i32 }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 4, align = 4
+            union Foo {
+                a: u32,
+                b: i32,
+            }
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        1,
+        r#"union Foo$0 { a: u32, b: i32 }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 4, align = 4
+            union Foo {
+                a: u32,
+                /* … */
+            }
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        0,
+        r#"union Foo$0 { a: u32, b: i32 }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 4, align = 4
+            union Foo { /* … */ }
+            ```
+        "#]],
+    );
+    check_hover_fields_limit(
+        None,
+        r#"union Foo$0 { a: u32, b: i32 }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            // size = 4, align = 4
+            union Foo
+            ```
+        "#]],
+    );
 }
 
 #[test]
@@ -1431,11 +1799,14 @@
                 ```
 
                 ```rust
-                struct Thing
+                struct Thing {
+                    x: u32,
+                }
                 ```
             "#]],
     );
-    check(
+    check_hover_fields_limit(
+        None,
         r#"
 struct Thing { x: u32 }
 impl Thing {
@@ -1456,9 +1827,9 @@
     );
     check(
         r#"
-enum Thing { A }
+struct Thing { x: u32 }
 impl Thing {
-    pub fn new() -> Self$0 { Thing::A }
+    fn new() -> Self$0 { Self { x: 0 } }
 }
 "#,
         expect![[r#"
@@ -1469,8 +1840,8 @@
                 ```
 
                 ```rust
-                enum Thing {
-                    A,
+                struct Thing {
+                    x: u32,
                 }
                 ```
             "#]],
@@ -1479,22 +1850,43 @@
         r#"
 enum Thing { A }
 impl Thing {
+    pub fn new() -> Self$0 { Thing::A }
+}
+"#,
+        expect![[r#"
+            *Self*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            enum Thing {
+                A,
+            }
+            ```
+        "#]],
+    );
+    check(
+        r#"
+enum Thing { A }
+impl Thing {
     pub fn thing(a: Self$0) {}
 }
 "#,
         expect![[r#"
-                *Self*
+            *Self*
 
-                ```rust
-                test
-                ```
+            ```rust
+            test
+            ```
 
-                ```rust
-                enum Thing {
-                    A,
-                }
-                ```
-            "#]],
+            ```rust
+            enum Thing {
+                A,
+            }
+            ```
+        "#]],
     );
     check(
         r#"
@@ -2382,8 +2774,8 @@
             ```rust
             // size = 16 (0x10), align = 8, niches = 254
             enum Foo {
-                Variant1(u8, u16),
-                Variant2(i32, u8, i64),
+                Variant1( /* … */ ),
+                Variant2( /* … */ ),
             }
             ```
         "#]],
@@ -4049,7 +4441,7 @@
             ```rust
             'label
             ```
-            "#]],
+        "#]],
     );
 }
 
@@ -4063,7 +4455,17 @@
             ```rust
             'lifetime
             ```
-            "#]],
+        "#]],
+    );
+    check(
+        r#"fn foo(_: &'static$0 ()) {}"#,
+        expect![[r#"
+            *'static*
+
+            ```rust
+            'static
+            ```
+        "#]],
     );
 }
 
@@ -6554,7 +6956,7 @@
 
             ```rust
             // size = 4, align = 4
-            RecordV { field: u32 }
+            RecordV { field: u32, }
             ```
         "#]],
     );
@@ -7398,9 +7800,12 @@
 "#,
         expect![[r#"
             *"🦀\u{1f980}\\\x41"*
-            ```text
-            🦀🦀\A
+            ```rust
+            &str
             ```
+            ___
+
+            value of literal: 🦀🦀\A
         "#]],
     );
     check(
@@ -7411,9 +7816,34 @@
 "#,
         expect![[r#"
             *r"🦀\u{1f980}\\\x41"*
-            ```text
-            🦀\u{1f980}\\\x41
+            ```rust
+            &str
             ```
+            ___
+
+            value of literal: 🦀\u{1f980}\\\x41
+        "#]],
+    );
+    check(
+        r#"
+fn main() {
+    $0r"🦀\u{1f980}\\\x41
+
+
+fsdghs";
+}
+"#,
+        expect![[r#"
+            *r"🦀\u{1f980}\\\x41
+
+
+            fsdghs"*
+            ```rust
+            &str
+            ```
+            ___
+
+            value of literal (truncated up to newline): 🦀\u{1f980}\\\x41
         "#]],
     );
 }
@@ -7428,9 +7858,12 @@
 "#,
         expect![[r#"
             *c"🦀\u{1f980}\\\x41"*
-            ```text
-            🦀🦀\A
+            ```rust
+            &{unknown}
             ```
+            ___
+
+            value of literal: 🦀🦀\A
         "#]],
     );
 }
@@ -7445,9 +7878,12 @@
 "#,
         expect![[r#"
             *b"\xF0\x9F\xA6\x80\\"*
-            ```text
-            [240, 159, 166, 128, 92]
+            ```rust
+            &[u8; 5]
             ```
+            ___
+
+            value of literal: [240, 159, 166, 128, 92]
         "#]],
     );
     check(
@@ -7458,9 +7894,12 @@
 "#,
         expect![[r#"
             *br"\xF0\x9F\xA6\x80\\"*
-            ```text
-            [92, 120, 70, 48, 92, 120, 57, 70, 92, 120, 65, 54, 92, 120, 56, 48, 92, 92]
+            ```rust
+            &[u8; 18]
             ```
+            ___
+
+            value of literal: [92, 120, 70, 48, 92, 120, 57, 70, 92, 120, 65, 54, 92, 120, 56, 48, 92, 92]
         "#]],
     );
 }
@@ -7475,9 +7914,12 @@
 "#,
         expect![[r#"
             *b'\xF0'*
-            ```text
-            0xF0
+            ```rust
+            u8
             ```
+            ___
+
+            value of literal: 0xF0
         "#]],
     );
     check(
@@ -7488,9 +7930,12 @@
 "#,
         expect![[r#"
             *b'\\'*
-            ```text
-            0x5C
+            ```rust
+            u8
             ```
+            ___
+
+            value of literal: 0x5C
         "#]],
     );
 }
@@ -7505,7 +7950,12 @@
 "#,
         expect![[r#"
             *'\x41'*
+            ```rust
+            char
+            ```
+            ___
 
+            value of literal: A
         "#]],
     );
     check(
@@ -7516,7 +7966,12 @@
 "#,
         expect![[r#"
             *'\\'*
+            ```rust
+            char
+            ```
+            ___
 
+            value of literal: \
         "#]],
     );
     check(
@@ -7527,7 +7982,12 @@
 "#,
         expect![[r#"
             *'\u{1f980}'*
+            ```rust
+            char
+            ```
+            ___
 
+            value of literal: 🦀
         "#]],
     );
 }
@@ -7542,9 +8002,12 @@
 "#,
         expect![[r#"
             *1.0*
-            ```text
-            1 (bits: 0x3FF0000000000000)
+            ```rust
+            f64
             ```
+            ___
+
+            value of literal: 1 (bits: 0x3FF0000000000000)
         "#]],
     );
     check(
@@ -7555,9 +8018,12 @@
 "#,
         expect![[r#"
             *1.0f32*
-            ```text
-            1 (bits: 0x3F800000)
+            ```rust
+            f32
             ```
+            ___
+
+            value of literal: 1 (bits: 0x3F800000)
         "#]],
     );
     check(
@@ -7568,9 +8034,12 @@
 "#,
         expect![[r#"
             *134e12*
-            ```text
-            134000000000000 (bits: 0x42DE77D399980000)
+            ```rust
+            f64
             ```
+            ___
+
+            value of literal: 134000000000000 (bits: 0x42DE77D399980000)
         "#]],
     );
     check(
@@ -7581,9 +8050,12 @@
 "#,
         expect![[r#"
             *1523527134274733643531312.0*
-            ```text
-            1523527134274733600000000 (bits: 0x44F429E9249F629B)
+            ```rust
+            f64
             ```
+            ___
+
+            value of literal: 1523527134274733600000000 (bits: 0x44F429E9249F629B)
         "#]],
     );
     check(
@@ -7594,9 +8066,12 @@
 "#,
         expect![[r#"
             *0.1ea123*
-            ```text
-            invalid float literal
+            ```rust
+            f64
             ```
+            ___
+
+            invalid literal: invalid float literal
         "#]],
     );
 }
@@ -7611,9 +8086,12 @@
 "#,
         expect![[r#"
             *34325236457856836345234*
-            ```text
-            34325236457856836345234 (0x744C659178614489D92|0b111010001001100011001011001000101111000011000010100010010001001110110010010)
+            ```rust
+            i32
             ```
+            ___
+
+            value of literal: 34325236457856836345234 (0x744C659178614489D92|0b111010001001100011001011001000101111000011000010100010010001001110110010010)
         "#]],
     );
     check(
@@ -7624,9 +8102,12 @@
 "#,
         expect![[r#"
             *134_123424_21*
-            ```text
-            13412342421 (0x31F701A95|0b1100011111011100000001101010010101)
+            ```rust
+            i32
             ```
+            ___
+
+            value of literal: 13412342421 (0x31F701A95|0b1100011111011100000001101010010101)
         "#]],
     );
     check(
@@ -7637,9 +8118,12 @@
 "#,
         expect![[r#"
             *0x12423423*
-            ```text
-            306328611 (0x12423423|0b10010010000100011010000100011)
+            ```rust
+            i32
             ```
+            ___
+
+            value of literal: 306328611 (0x12423423|0b10010010000100011010000100011)
         "#]],
     );
     check(
@@ -7650,9 +8134,12 @@
 "#,
         expect![[r#"
             *0b1111_1111*
-            ```text
-            255 (0xFF|0b11111111)
+            ```rust
+            i32
             ```
+            ___
+
+            value of literal: 255 (0xFF|0b11111111)
         "#]],
     );
     check(
@@ -7663,9 +8150,12 @@
 "#,
         expect![[r#"
             *0o12345*
-            ```text
-            5349 (0x14E5|0b1010011100101)
+            ```rust
+            i32
             ```
+            ___
+
+            value of literal: 5349 (0x14E5|0b1010011100101)
         "#]],
     );
     check(
@@ -7676,9 +8166,12 @@
 "#,
         expect![[r#"
             *0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_F*
-            ```text
-            number too large to fit in target type
+            ```rust
+            i32
             ```
+            ___
+
+            invalid literal: number too large to fit in target type
         "#]],
     );
 }
@@ -7864,8 +8357,8 @@
                                 file_id: FileId(
                                     1,
                                 ),
-                                full_range: 6290..6498,
-                                focus_range: 6355..6361,
+                                full_range: 7791..7999,
+                                focus_range: 7856..7862,
                                 name: "Future",
                                 kind: Trait,
                                 container_name: "future",
@@ -7878,8 +8371,8 @@
                                 file_id: FileId(
                                     1,
                                 ),
-                                full_range: 7128..7594,
-                                focus_range: 7172..7180,
+                                full_range: 8629..9095,
+                                focus_range: 8673..8681,
                                 name: "Iterator",
                                 kind: Trait,
                                 container_name: "iterator",
@@ -7936,7 +8429,9 @@
 
             ```rust
             // size = 16 (0x10), align = 8, niches = 1
-            struct Pedro<'a>
+            struct Pedro<'a> {
+                hola: &str,
+            }
             ```
         "#]],
     )
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 15eecd1..dda5a00 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -496,7 +496,7 @@
     config: &InlayHintsConfig,
     hasher: impl Fn(&InlayHint) -> u64,
 ) -> Option<InlayHint> {
-    let _p = tracing::span!(tracing::Level::INFO, "inlay_hints").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "inlay_hints_resolve").entered();
     let sema = Semantics::new(db);
     let file = sema.parse(file_id);
     let file = file.syntax();
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index 07b9f9c..0cb8c48 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
@@ -332,6 +332,25 @@
     }
 
     #[test]
+    fn lt_hints() {
+        check_types(
+            r#"
+struct S<'lt>;
+
+fn f<'a>() {
+    let x = S::<'static>;
+      //^ S<'static>
+    let y = S::<'_>;
+      //^ S
+    let z = S::<'a>;
+      //^ S<'a>
+
+}
+"#,
+        );
+    }
+
+    #[test]
     fn fn_hints() {
         check_types(
             r#"
@@ -341,7 +360,7 @@
 fn foo2() -> impl Fn(f64, f64) { loop {} }
 fn foo3() -> impl Fn(f64, f64) -> u32 { loop {} }
 fn foo4() -> &'static dyn Fn(f64, f64) -> u32 { loop {} }
-fn foo5() -> &'static dyn Fn(&'static dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
+fn foo5() -> &'static for<'a> dyn Fn(&'a dyn Fn(f64, f64) -> u32, f64) -> u32 { loop {} }
 fn foo6() -> impl Fn(f64, f64) -> u32 + Sized { loop {} }
 fn foo7() -> *const (impl Fn(f64, f64) -> u32 + Sized) { loop {} }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
index 08760c0..68854c3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
@@ -211,6 +211,7 @@
             }
         }
         Definition::BuiltinType(..) => Type,
+        Definition::BuiltinLifetime(_) => TypeParameter,
         Definition::SelfType(..) => TypeAlias,
         Definition::GenericParam(..) => TypeParameter,
         Definition::Local(it) => {
@@ -316,6 +317,7 @@
         Definition::GenericParam(_)
         | Definition::Label(_)
         | Definition::DeriveHelper(_)
+        | Definition::BuiltinLifetime(_)
         | Definition::BuiltinAttr(_)
         | Definition::ToolModule(_) => return None,
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
index 2123c98..fc836d5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -235,9 +235,11 @@
             Definition::TraitAlias(it) => it.try_to_nav(db),
             Definition::TypeAlias(it) => it.try_to_nav(db),
             Definition::ExternCrateDecl(it) => Some(it.try_to_nav(db)?),
-            Definition::BuiltinType(_) | Definition::TupleField(_) => None,
-            Definition::ToolModule(_) => None,
-            Definition::BuiltinAttr(_) => None,
+            Definition::BuiltinLifetime(_)
+            | Definition::BuiltinType(_)
+            | Definition::TupleField(_)
+            | Definition::ToolModule(_)
+            | Definition::BuiltinAttr(_) => None,
             // FIXME: The focus range should be set to the helper declaration
             Definition::DeriveHelper(it) => it.derive().try_to_nav(db),
         }
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index b6c6753..64ffa59 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -15,6 +15,7 @@
     FxHashMap, FxHashSet, RootDatabase, SymbolKind,
 };
 use itertools::Itertools;
+use span::TextSize;
 use stdx::{always, format_to};
 use syntax::{
     ast::{self, AstNode},
@@ -48,16 +49,15 @@
 
 #[derive(Debug, Clone, Hash, PartialEq, Eq)]
 pub enum RunnableKind {
-    Test { test_id: TestId, attr: TestAttr },
     TestMod { path: String },
+    Test { test_id: TestId, attr: TestAttr },
     Bench { test_id: TestId },
     DocTest { test_id: TestId },
     Bin,
 }
 
-#[cfg(test)]
-#[derive(Debug, Clone, Hash, PartialEq, Eq)]
-enum RunnableTestKind {
+#[derive(Debug, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
+enum RunnableDiscKind {
     Test,
     TestMod,
     DocTest,
@@ -65,6 +65,18 @@
     Bin,
 }
 
+impl RunnableKind {
+    fn disc(&self) -> RunnableDiscKind {
+        match self {
+            RunnableKind::TestMod { .. } => RunnableDiscKind::TestMod,
+            RunnableKind::Test { .. } => RunnableDiscKind::Test,
+            RunnableKind::DocTest { .. } => RunnableDiscKind::DocTest,
+            RunnableKind::Bench { .. } => RunnableDiscKind::Bench,
+            RunnableKind::Bin => RunnableDiscKind::Bin,
+        }
+    }
+}
+
 impl Runnable {
     // test package::module::testname
     pub fn label(&self, target: Option<String>) -> String {
@@ -97,17 +109,6 @@
         s.push_str(suffix);
         s
     }
-
-    #[cfg(test)]
-    fn test_kind(&self) -> RunnableTestKind {
-        match &self.kind {
-            RunnableKind::TestMod { .. } => RunnableTestKind::TestMod,
-            RunnableKind::Test { .. } => RunnableTestKind::Test,
-            RunnableKind::DocTest { .. } => RunnableTestKind::DocTest,
-            RunnableKind::Bench { .. } => RunnableTestKind::Bench,
-            RunnableKind::Bin => RunnableTestKind::Bin,
-        }
-    }
 }
 
 // Feature: Run
@@ -193,6 +194,20 @@
             r
         })
     }));
+    res.sort_by(|Runnable { nav, kind, .. }, Runnable { nav: nav_b, kind: kind_b, .. }| {
+        // full_range.start < focus_range.start < name, should give us a decent unique ordering
+        nav.full_range
+            .start()
+            .cmp(&nav_b.full_range.start())
+            .then_with(|| {
+                let t_0 = || TextSize::from(0);
+                nav.focus_range
+                    .map_or_else(t_0, |it| it.start())
+                    .cmp(&nav_b.focus_range.map_or_else(t_0, |it| it.start()))
+            })
+            .then_with(|| kind.disc().cmp(&kind_b.disc()))
+            .then_with(|| nav.name.cmp(&nav_b.name))
+    });
     res
 }
 
@@ -571,13 +586,12 @@
 
     fn check(ra_fixture: &str, expect: Expect) {
         let (analysis, position) = fixture::position(ra_fixture);
-        let mut runnables = analysis.runnables(position.file_id).unwrap();
-        runnables.sort_by_key(|it| (it.nav.full_range.start(), it.nav.name.clone()));
-
-        let result = runnables
+        let result = analysis
+            .runnables(position.file_id)
+            .unwrap()
             .into_iter()
             .map(|runnable| {
-                let mut a = format!("({:?}, {:?}", runnable.test_kind(), runnable.nav);
+                let mut a = format!("({:?}, {:?}", runnable.kind.disc(), runnable.nav);
                 if runnable.use_name_in_title {
                     a.push_str(", true");
                 }
@@ -609,6 +623,9 @@
 #[export_name = "main"]
 fn __cortex_m_rt_main_trampoline() {}
 
+#[unsafe(export_name = "main")]
+fn __cortex_m_rt_main_trampoline_unsafe() {}
+
 #[test]
 fn test_foo() {}
 
@@ -628,13 +645,14 @@
 "#,
             expect![[r#"
                 [
-                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..253, name: \"\", kind: Module })",
+                    "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 0..331, name: \"\", kind: Module })",
                     "(Bin, NavigationTarget { file_id: FileId(0), full_range: 1..13, focus_range: 4..8, name: \"main\", kind: Function })",
                     "(Bin, NavigationTarget { file_id: FileId(0), full_range: 15..76, focus_range: 42..71, name: \"__cortex_m_rt_main_trampoline\", kind: Function })",
-                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 78..102, focus_range: 89..97, name: \"test_foo\", kind: Function })",
-                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 104..155, focus_range: 136..150, name: \"test_full_path\", kind: Function })",
-                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 157..191, focus_range: 178..186, name: \"test_foo\", kind: Function })",
-                    "(Bench, NavigationTarget { file_id: FileId(0), full_range: 193..215, focus_range: 205..210, name: \"bench\", kind: Function })",
+                    "(Bin, NavigationTarget { file_id: FileId(0), full_range: 78..154, focus_range: 113..149, name: \"__cortex_m_rt_main_trampoline_unsafe\", kind: Function })",
+                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 156..180, focus_range: 167..175, name: \"test_foo\", kind: Function })",
+                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 182..233, focus_range: 214..228, name: \"test_full_path\", kind: Function })",
+                    "(Test, NavigationTarget { file_id: FileId(0), full_range: 235..269, focus_range: 256..264, name: \"test_foo\", kind: Function })",
+                    "(Bench, NavigationTarget { file_id: FileId(0), full_range: 271..293, focus_range: 283..288, name: \"bench\", kind: Function })",
                 ]
             "#]],
         );
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index ca013da..0d2311b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -167,7 +167,8 @@
             keywords: true,
             format: crate::HoverDocFormat::Markdown,
             max_trait_assoc_items_count: None,
-            max_struct_field_count: None,
+            max_fields_count: Some(5),
+            max_enum_variants_count: Some(5),
         };
         let tokens = tokens.filter(|token| {
             matches!(
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs
index 5913ca5..0439e50 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/escape.rs
@@ -25,7 +25,7 @@
 }
 
 pub(super) fn highlight_escape_char(stack: &mut Highlights, char: &Char, start: TextSize) {
-    if char.value().is_none() {
+    if char.value().is_err() {
         // We do not emit invalid escapes highlighting here. The lexer would likely be in a bad
         // state and this token contains junks, since `'` is not a reliable delimiter (consider
         // lifetimes). Nonetheless, parser errors should already be emitted.
@@ -48,7 +48,7 @@
 }
 
 pub(super) fn highlight_escape_byte(stack: &mut Highlights, byte: &Byte, start: TextSize) {
-    if byte.value().is_none() {
+    if byte.value().is_err() {
         // See `highlight_escape_char` for why no error highlighting here.
         return;
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
index a72f505..3b784eb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
@@ -484,6 +484,7 @@
             h
         }
         Definition::BuiltinType(_) => Highlight::new(HlTag::BuiltinType),
+        Definition::BuiltinLifetime(_) => Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam)),
         Definition::Static(s) => {
             let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static));
 
@@ -542,13 +543,14 @@
     let def_crate = def.krate(db);
     let is_from_other_crate = def_crate != Some(krate);
     let is_from_builtin_crate = def_crate.map_or(false, |def_crate| def_crate.is_builtin(db));
-    let is_builtin_type = matches!(def, Definition::BuiltinType(_));
-    let is_public = def.visibility(db) == Some(hir::Visibility::Public);
-
-    match (is_from_other_crate, is_builtin_type, is_public) {
-        (true, false, _) => h |= HlMod::Library,
-        (false, _, true) => h |= HlMod::Public,
-        _ => {}
+    let is_builtin = matches!(
+        def,
+        Definition::BuiltinType(_) | Definition::BuiltinLifetime(_) | Definition::BuiltinAttr(_)
+    );
+    match is_from_other_crate {
+        true if !is_builtin => h |= HlMod::Library,
+        false if def.visibility(db) == Some(hir::Visibility::Public) => h |= HlMod::Public,
+        _ => (),
     }
 
     if is_from_builtin_crate {
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
index 6bf13ff..f9b8a22 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/inject.rs
@@ -30,7 +30,7 @@
     if !active_parameter.ident().map_or(false, |name| name.text().starts_with("ra_fixture")) {
         return None;
     }
-    let value = literal.value()?;
+    let value = literal.value().ok()?;
 
     if let Some(range) = literal.open_quote_text_range() {
         hl.add(HlRange { range, highlight: HlTag::StringLiteral.into(), binding_hash: None })
@@ -299,6 +299,7 @@
         Definition::Trait(_) => SymbolKind::Trait,
         Definition::TraitAlias(_) => SymbolKind::TraitAlias,
         Definition::TypeAlias(_) => SymbolKind::TypeAlias,
+        Definition::BuiltinLifetime(_) => SymbolKind::LifetimeParam,
         Definition::BuiltinType(_) => return HlTag::BuiltinType,
         Definition::Macro(_) => SymbolKind::Macro,
         Definition::Field(_) | Definition::TupleField(_) => SymbolKind::Field,
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
index de902b5..cad5a8b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
@@ -45,7 +45,7 @@
 .invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
 .unresolved_reference    { color: #FC5555; text-decoration: wavy underline; }
 </style>
-<pre><code><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">allow</span><span class="parenthesis attribute">(</span><span class="none attribute">dead_code</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<pre><code><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">allow</span><span class="parenthesis attribute">(</span><span class="none attribute">dead_code</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute library">rustfmt</span><span class="operator attribute">::</span><span class="tool_module attribute library">skip</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="module attribute crate_root library">proc_macros</span><span class="operator attribute">::</span><span class="attribute attribute library">identity</span><span class="attribute_bracket attribute">]</span>
 <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="derive attribute default_library library">Default</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
index 366895c..893e3c0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
@@ -49,5 +49,5 @@
 
 <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
     <span class="keyword">let</span> <span class="variable declaration">foo</span> <span class="operator">=</span> <span class="enum_variant default_library library">Some</span><span class="parenthesis">(</span><span class="numeric_literal">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
-    <span class="keyword">let</span> <span class="variable declaration">nums</span> <span class="operator">=</span> <span class="module default_library library">iter</span><span class="operator">::</span><span class="function default_library library">repeat</span><span class="parenthesis">(</span><span class="variable">foo</span><span class="operator">.</span><span class="method consuming default_library library">unwrap</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+    <span class="keyword">let</span> <span class="variable declaration">nums</span> <span class="operator">=</span> <span class="module default_library library">iter</span><span class="operator">::</span><span class="function default_library library">repeat</span><span class="parenthesis">(</span><span class="variable">foo</span><span class="operator">.</span><span class="method default_library library">unwrap</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span><span class="semicolon">;</span>
 <span class="brace">}</span></code></pre>
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index b2ca6e1..35650bb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -79,7 +79,7 @@
     <span class="comment documentation">/// # Examples</span>
     <span class="comment documentation">///</span>
     <span class="comment documentation">/// ```</span>
-    <span class="comment documentation">///</span><span class="comment documentation"> #</span><span class="none injected"> </span><span class="attribute_bracket attribute injected">#</span><span class="attribute_bracket attribute injected">!</span><span class="attribute_bracket attribute injected">[</span><span class="builtin_attr attribute injected library">allow</span><span class="parenthesis attribute injected">(</span><span class="none attribute injected">unused_mut</span><span class="parenthesis attribute injected">)</span><span class="attribute_bracket attribute injected">]</span>
+    <span class="comment documentation">///</span><span class="comment documentation"> #</span><span class="none injected"> </span><span class="attribute_bracket attribute injected">#</span><span class="attribute_bracket attribute injected">!</span><span class="attribute_bracket attribute injected">[</span><span class="builtin_attr attribute injected">allow</span><span class="parenthesis attribute injected">(</span><span class="none attribute injected">unused_mut</span><span class="parenthesis attribute injected">)</span><span class="attribute_bracket attribute injected">]</span>
     <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="keyword injected">mut</span><span class="none injected"> </span><span class="variable declaration injected mutable">foo</span><span class="colon injected">:</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
     <span class="comment documentation">/// ```</span>
     <span class="keyword">pub</span> <span class="keyword const">const</span> <span class="keyword">fn</span> <span class="function associated const declaration public static">new</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="struct">Foo</span> <span class="brace">{</span>
@@ -162,12 +162,12 @@
 <span class="comment documentation">///</span>
 <span class="comment documentation">/// ```</span>
 <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">not</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"false"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">not</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"false"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"</span><span class="keyword control injected">loop</span><span class="none injected"> </span><span class="brace injected">{</span><span class="brace injected">}</span><span class="string_literal attribute">"</span><span class="attribute_bracket attribute">]</span>
 <span class="comment documentation">/// ```</span>
 <span class="comment documentation">///</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"alloc"</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"```rust"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">not</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"alloc"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"```ignore"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"alloc"</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"```rust"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">cfg_attr</span><span class="parenthesis attribute">(</span><span class="none attribute">not</span><span class="parenthesis attribute">(</span><span class="none attribute">feature</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"alloc"</span><span class="parenthesis attribute">)</span><span class="comma attribute">,</span> <span class="none attribute">doc</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"```ignore"</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="comment documentation">///</span><span class="comment documentation"> </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="punctuation injected">_</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="function injected">example</span><span class="parenthesis injected">(</span><span class="operator injected">&</span><span class="module injected">alloc</span><span class="operator injected">::</span><span class="macro injected">vec</span><span class="macro_bang injected">!</span><span class="bracket injected macro">[</span><span class="numeric_literal injected macro">1</span><span class="comma injected macro">,</span><span class="none injected"> </span><span class="numeric_literal injected macro">2</span><span class="comma injected macro">,</span><span class="none injected"> </span><span class="numeric_literal injected macro">3</span><span class="bracket injected macro">]</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
 <span class="comment documentation">/// ```</span>
 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration public">mix_and_match</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
index 5234d36..413edb6 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
@@ -49,13 +49,13 @@
 <span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
 
 <span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration public">ops</span> <span class="brace">{</span>
-    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_once"</span><span class="attribute_bracket attribute">]</span>
+    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_once"</span><span class="attribute_bracket attribute">]</span>
     <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">FnOnce</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
 
-    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_mut"</span><span class="attribute_bracket attribute">]</span>
+    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn_mut"</span><span class="attribute_bracket attribute">]</span>
     <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">FnMut</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span><span class="colon">:</span> <span class="trait public">FnOnce</span><span class="angle">&lt;</span><span class="type_param">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
 
-    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn"</span><span class="attribute_bracket attribute">]</span>
+    <span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">lang</span> <span class="operator attribute">=</span> <span class="string_literal attribute">"fn"</span><span class="attribute_bracket attribute">]</span>
     <span class="keyword">pub</span> <span class="keyword">trait</span> <span class="trait declaration public">Fn</span><span class="angle">&lt;</span><span class="type_param declaration">Args</span><span class="angle">&gt;</span><span class="colon">:</span> <span class="trait public">FnMut</span><span class="angle">&lt;</span><span class="type_param">Args</span><span class="angle">&gt;</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index 7a07d17..22706de 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -158,9 +158,9 @@
     <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">ничоси</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
 
     <span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> "</span><span class="comma macro">,</span> <span class="unresolved_reference macro">thingy</span><span class="comma macro">,</span> <span class="unresolved_reference macro">n2</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro default_library library">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro default_library library">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro default_library library">panic</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"more </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
-    <span class="macro default_library library">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
+    <span class="macro default_library library">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"{}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro default_library library">assert</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="bool_literal macro">true</span><span class="comma macro">,</span> <span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> asdasd"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="macro">toho</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"{}fmt"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
     <span class="keyword">let</span> <span class="variable declaration">i</span><span class="colon">:</span> <span class="builtin_type">u64</span> <span class="operator">=</span> <span class="numeric_literal">3</span><span class="semicolon">;</span>
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 15d6be6..be61768 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -69,7 +69,7 @@
     <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="method associated declaration reference unsafe">unsafe_method</span><span class="parenthesis">(</span><span class="punctuation">&</span><span class="self_keyword declaration reference">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 <span class="brace">}</span>
 
-<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">repr</span><span class="parenthesis attribute">(</span><span class="none attribute">packed</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
+<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute">repr</span><span class="parenthesis attribute">(</span><span class="none attribute">packed</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
 <span class="keyword">struct</span> <span class="struct declaration">Packed</span> <span class="brace">{</span>
     <span class="field declaration">a</span><span class="colon">:</span> <span class="builtin_type">u16</span><span class="comma">,</span>
 <span class="brace">}</span>
diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index 31b0c8c..76940ab 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -17,6 +17,7 @@
 use proc_macro_api::{MacroDylib, ProcMacroServer};
 use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace};
 use span::Span;
+use tracing::{instrument, Level};
 use vfs::{file_set::FileSetConfig, loader::Handle, AbsPath, AbsPathBuf, VfsPath};
 
 pub struct LoadCargoConfig {
@@ -50,6 +51,7 @@
     load_workspace(workspace, &cargo_config.extra_env, load_config)
 }
 
+#[instrument(skip_all)]
 pub fn load_workspace(
     ws: ProjectWorkspace,
     extra_env: &FxHashMap<String, String>,
@@ -66,9 +68,9 @@
     let proc_macro_server = match &load_config.with_proc_macro_server {
         ProcMacroServerChoice::Sysroot => ws
             .find_sysroot_proc_macro_srv()
-            .and_then(|it| ProcMacroServer::spawn(it, extra_env).map_err(Into::into)),
+            .and_then(|it| ProcMacroServer::spawn(&it, extra_env).map_err(Into::into)),
         ProcMacroServerChoice::Explicit(path) => {
-            ProcMacroServer::spawn(path.clone(), extra_env).map_err(Into::into)
+            ProcMacroServer::spawn(path, extra_env).map_err(Into::into)
         }
         ProcMacroServerChoice::None => Err(anyhow::format_err!("proc macro server disabled")),
     };
@@ -333,9 +335,7 @@
     vfs: &mut vfs::Vfs,
     receiver: &Receiver<vfs::loader::Message>,
 ) -> RootDatabase {
-    let (ProjectWorkspace::Cargo { toolchain, target_layout, .. }
-    | ProjectWorkspace::Json { toolchain, target_layout, .. }
-    | ProjectWorkspace::DetachedFile { toolchain, target_layout, .. }) = ws;
+    let ProjectWorkspace { toolchain, target_layout, .. } = ws;
 
     let lru_cap = std::env::var("RA_LRU_CAP").ok().and_then(|it| it.parse::<usize>().ok());
     let mut db = RootDatabase::new(lru_cap);
@@ -352,6 +352,8 @@
                 }
             }
             vfs::loader::Message::Loaded { files } | vfs::loader::Message::Changed { files } => {
+                let _p = tracing::span!(Level::INFO, "load_cargo::load_crate_craph/LoadedChanged")
+                    .entered();
                 for (path, contents) in files {
                     vfs.set_file_contents(path.into(), contents);
                 }
@@ -359,8 +361,8 @@
         }
     }
     let changes = vfs.take_changes();
-    for file in changes {
-        if let vfs::Change::Create(v) | vfs::Change::Modify(v) = file.change {
+    for (_, file) in changes {
+        if let vfs::Change::Create(v, _) | vfs::Change::Modify(v, _) = file.change {
             if let Ok(text) = String::from_utf8(v) {
                 analysis_change.change_file(file.file_id, Some(text))
             }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
index f4bbaef..f73e188 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
@@ -10,7 +10,7 @@
 
 use crate::{
     parser::{MetaVarKind, Op, RepeatKind, Separator},
-    syntax_node_to_token_tree, DeclarativeMacro, DummyTestSpanMap, DUMMY,
+    syntax_node_to_token_tree, DeclarativeMacro, DocCommentDesugarMode, DummyTestSpanMap, DUMMY,
 };
 
 #[test]
@@ -78,6 +78,7 @@
                 rule.token_tree().unwrap().syntax(),
                 DummyTestSpanMap,
                 DUMMY,
+                DocCommentDesugarMode::Mbe,
             );
             (id, def_tt)
         })
diff --git a/src/tools/rust-analyzer/crates/mbe/src/lib.rs b/src/tools/rust-analyzer/crates/mbe/src/lib.rs
index d5de563..6920832 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/lib.rs
@@ -34,7 +34,7 @@
 pub use crate::syntax_bridge::{
     parse_exprs_with_sep, parse_to_token_tree, parse_to_token_tree_static_span,
     syntax_node_to_token_tree, syntax_node_to_token_tree_modified, token_tree_to_syntax_node,
-    SpanMapper,
+    DocCommentDesugarMode, SpanMapper,
 };
 
 pub use crate::syntax_bridge::dummy_test_span_utils::*;
diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
index 3230eeb..412e492 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
@@ -69,18 +69,28 @@
     }
 }
 
+/// Doc comment desugaring differs between mbe and proc-macros.
+#[derive(Copy, Clone, PartialEq, Eq)]
+pub enum DocCommentDesugarMode {
+    /// Desugars doc comments as quoted raw strings
+    Mbe,
+    /// Desugars doc comments as quoted strings
+    ProcMacro,
+}
+
 /// Converts a syntax tree to a [`tt::Subtree`] using the provided span map to populate the
 /// subtree's spans.
 pub fn syntax_node_to_token_tree<Ctx, SpanMap>(
     node: &SyntaxNode,
     map: SpanMap,
     span: SpanData<Ctx>,
+    mode: DocCommentDesugarMode,
 ) -> tt::Subtree<SpanData<Ctx>>
 where
     SpanData<Ctx>: Copy + fmt::Debug,
     SpanMap: SpanMapper<SpanData<Ctx>>,
 {
-    let mut c = Converter::new(node, map, Default::default(), Default::default(), span);
+    let mut c = Converter::new(node, map, Default::default(), Default::default(), span, mode);
     convert_tokens(&mut c)
 }
 
@@ -93,12 +103,13 @@
     append: FxHashMap<SyntaxElement, Vec<tt::Leaf<SpanData<Ctx>>>>,
     remove: FxHashSet<SyntaxElement>,
     call_site: SpanData<Ctx>,
+    mode: DocCommentDesugarMode,
 ) -> tt::Subtree<SpanData<Ctx>>
 where
     SpanMap: SpanMapper<SpanData<Ctx>>,
     SpanData<Ctx>: Copy + fmt::Debug,
 {
-    let mut c = Converter::new(node, map, append, remove, call_site);
+    let mut c = Converter::new(node, map, append, remove, call_site, mode);
     convert_tokens(&mut c)
 }
 
@@ -165,7 +176,8 @@
     if lexed.errors().next().is_some() {
         return None;
     }
-    let mut conv = RawConverter { lexed, anchor, pos: 0, ctx };
+    let mut conv =
+        RawConverter { lexed, anchor, pos: 0, ctx, mode: DocCommentDesugarMode::ProcMacro };
     Some(convert_tokens(&mut conv))
 }
 
@@ -178,7 +190,8 @@
     if lexed.errors().next().is_some() {
         return None;
     }
-    let mut conv = StaticRawConverter { lexed, pos: 0, span };
+    let mut conv =
+        StaticRawConverter { lexed, pos: 0, span, mode: DocCommentDesugarMode::ProcMacro };
     Some(convert_tokens(&mut conv))
 }
 
@@ -405,7 +418,7 @@
 /// That is, strips leading `///` (or `/**`, etc)
 /// and strips the ending `*/`
 /// And then quote the string, which is needed to convert to `tt::Literal`
-fn doc_comment_text(comment: &ast::Comment) -> SmolStr {
+fn doc_comment_text(comment: &ast::Comment, mode: DocCommentDesugarMode) -> SmolStr {
     let prefix_len = comment.prefix().len();
     let mut text = &comment.text()[prefix_len..];
 
@@ -414,26 +427,34 @@
         text = &text[0..text.len() - 2];
     }
 
-    let mut num_of_hashes = 0;
-    let mut count = 0;
-    for ch in text.chars() {
-        count = match ch {
-            '"' => 1,
-            '#' if count > 0 => count + 1,
-            _ => 0,
-        };
-        num_of_hashes = num_of_hashes.max(count);
-    }
+    let text = match mode {
+        DocCommentDesugarMode::Mbe => {
+            let mut num_of_hashes = 0;
+            let mut count = 0;
+            for ch in text.chars() {
+                count = match ch {
+                    '"' => 1,
+                    '#' if count > 0 => count + 1,
+                    _ => 0,
+                };
+                num_of_hashes = num_of_hashes.max(count);
+            }
 
-    // Quote raw string with delimiters
-    // Note that `tt::Literal` expect an escaped string
-    let text = format!("r{delim}\"{text}\"{delim}", delim = "#".repeat(num_of_hashes));
+            // Quote raw string with delimiters
+            // Note that `tt::Literal` expect an escaped string
+            format!(r#"r{delim}"{text}"{delim}"#, delim = "#".repeat(num_of_hashes))
+        }
+        // Quote string with delimiters
+        // Note that `tt::Literal` expect an escaped string
+        DocCommentDesugarMode::ProcMacro => format!(r#""{}""#, text.escape_debug()),
+    };
     text.into()
 }
 
 fn convert_doc_comment<S: Copy>(
     token: &syntax::SyntaxToken,
     span: S,
+    mode: DocCommentDesugarMode,
 ) -> Option<Vec<tt::TokenTree<S>>> {
     cov_mark::hit!(test_meta_doc_comments);
     let comment = ast::Comment::cast(token.clone())?;
@@ -451,7 +472,7 @@
     };
 
     let mk_doc_literal = |comment: &ast::Comment| {
-        let lit = tt::Literal { text: doc_comment_text(comment), span };
+        let lit = tt::Literal { text: doc_comment_text(comment, mode), span };
 
         tt::TokenTree::from(tt::Leaf::from(lit))
     };
@@ -479,12 +500,14 @@
     pos: usize,
     anchor: SpanAnchor,
     ctx: Ctx,
+    mode: DocCommentDesugarMode,
 }
 /// A raw token (straight from lexer) converter that gives every token the same span.
 struct StaticRawConverter<'a, S> {
     lexed: parser::LexedStr<'a>,
     pos: usize,
     span: S,
+    mode: DocCommentDesugarMode,
 }
 
 trait SrcToken<Ctx, S> {
@@ -553,7 +576,7 @@
         span: SpanData<Ctx>,
     ) -> Option<Vec<tt::TokenTree<SpanData<Ctx>>>> {
         let text = self.lexed.text(token);
-        convert_doc_comment(&doc_comment(text), span)
+        convert_doc_comment(&doc_comment(text), span, self.mode)
     }
 
     fn bump(&mut self) -> Option<(Self::Token, TextRange)> {
@@ -592,7 +615,7 @@
 
     fn convert_doc_comment(&self, &token: &usize, span: S) -> Option<Vec<tt::TokenTree<S>>> {
         let text = self.lexed.text(token);
-        convert_doc_comment(&doc_comment(text), span)
+        convert_doc_comment(&doc_comment(text), span, self.mode)
     }
 
     fn bump(&mut self) -> Option<(Self::Token, TextRange)> {
@@ -634,6 +657,7 @@
     append: FxHashMap<SyntaxElement, Vec<tt::Leaf<S>>>,
     remove: FxHashSet<SyntaxElement>,
     call_site: S,
+    mode: DocCommentDesugarMode,
 }
 
 impl<SpanMap, S> Converter<SpanMap, S> {
@@ -643,6 +667,7 @@
         append: FxHashMap<SyntaxElement, Vec<tt::Leaf<S>>>,
         remove: FxHashSet<SyntaxElement>,
         call_site: S,
+        mode: DocCommentDesugarMode,
     ) -> Self {
         let mut this = Converter {
             current: None,
@@ -654,6 +679,7 @@
             remove,
             call_site,
             current_leaves: vec![],
+            mode,
         };
         let first = this.next_token();
         this.current = first;
@@ -755,7 +781,7 @@
 {
     type Token = SynToken<S>;
     fn convert_doc_comment(&self, token: &Self::Token, span: S) -> Option<Vec<tt::TokenTree<S>>> {
-        convert_doc_comment(token.token(), span)
+        convert_doc_comment(token.token(), span, self.mode)
     }
 
     fn bump(&mut self) -> Option<(Self::Token, TextRange)> {
diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs
index bbfe378..2988fb3 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs
@@ -7,11 +7,16 @@
     Leaf, Punct, Spacing,
 };
 
-use crate::{syntax_node_to_token_tree, DummyTestSpanMap, DUMMY};
+use crate::{syntax_node_to_token_tree, DocCommentDesugarMode, DummyTestSpanMap, DUMMY};
 
 fn check_punct_spacing(fixture: &str) {
     let source_file = ast::SourceFile::parse(fixture, span::Edition::CURRENT).ok().unwrap();
-    let subtree = syntax_node_to_token_tree(source_file.syntax(), DummyTestSpanMap, DUMMY);
+    let subtree = syntax_node_to_token_tree(
+        source_file.syntax(),
+        DummyTestSpanMap,
+        DUMMY,
+        DocCommentDesugarMode::Mbe,
+    );
     let mut annotations: FxHashMap<_, _> = extract_annotations(fixture)
         .into_iter()
         .map(|(range, annotation)| {
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs
index c13a194..82e4d66 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/attributes.rs
@@ -36,8 +36,33 @@
     attr.complete(p, ATTR);
 }
 
+// test metas
+// #![simple_ident]
+// #![simple::path]
+// #![simple_ident_expr = ""]
+// #![simple::path::Expr = ""]
+// #![simple_ident_tt(a b c)]
+// #![simple_ident_tt[a b c]]
+// #![simple_ident_tt{a b c}]
+// #![simple::path::tt(a b c)]
+// #![simple::path::tt[a b c]]
+// #![simple::path::tt{a b c}]
+// #![unsafe(simple_ident)]
+// #![unsafe(simple::path)]
+// #![unsafe(simple_ident_expr = "")]
+// #![unsafe(simple::path::Expr = "")]
+// #![unsafe(simple_ident_tt(a b c))]
+// #![unsafe(simple_ident_tt[a b c])]
+// #![unsafe(simple_ident_tt{a b c})]
+// #![unsafe(simple::path::tt(a b c))]
+// #![unsafe(simple::path::tt[a b c])]
+// #![unsafe(simple::path::tt{a b c})]
 pub(super) fn meta(p: &mut Parser<'_>) {
     let meta = p.start();
+    let is_unsafe = p.eat(T![unsafe]);
+    if is_unsafe {
+        p.expect(T!['(']);
+    }
     paths::use_path(p);
 
     match p.current() {
@@ -50,6 +75,9 @@
         T!['('] | T!['['] | T!['{'] => items::token_tree(p),
         _ => {}
     }
+    if is_unsafe {
+        p.expect(T![')']);
+    }
 
     meta.complete(p, META);
 }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rast
new file mode 100644
index 0000000..b1ac60b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rast
@@ -0,0 +1,457 @@
+SOURCE_FILE
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "simple"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "path"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_expr"
+      WHITESPACE " "
+      EQ "="
+      WHITESPACE " "
+      LITERAL
+        STRING "\"\""
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "Expr"
+      WHITESPACE " "
+      EQ "="
+      WHITESPACE " "
+      LITERAL
+        STRING "\"\""
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_tt"
+      TOKEN_TREE
+        L_PAREN "("
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_tt"
+      TOKEN_TREE
+        L_BRACK "["
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_BRACK "]"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_tt"
+      TOKEN_TREE
+        L_CURLY "{"
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_CURLY "}"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "tt"
+      TOKEN_TREE
+        L_PAREN "("
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "tt"
+      TOKEN_TREE
+        L_BRACK "["
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_BRACK "]"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "tt"
+      TOKEN_TREE
+        L_CURLY "{"
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_CURLY "}"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "simple"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "path"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_expr"
+      WHITESPACE " "
+      EQ "="
+      WHITESPACE " "
+      LITERAL
+        STRING "\"\""
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "Expr"
+      WHITESPACE " "
+      EQ "="
+      WHITESPACE " "
+      LITERAL
+        STRING "\"\""
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_tt"
+      TOKEN_TREE
+        L_PAREN "("
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_PAREN ")"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_tt"
+      TOKEN_TREE
+        L_BRACK "["
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_BRACK "]"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "simple_ident_tt"
+      TOKEN_TREE
+        L_CURLY "{"
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_CURLY "}"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "tt"
+      TOKEN_TREE
+        L_PAREN "("
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_PAREN ")"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "tt"
+      TOKEN_TREE
+        L_BRACK "["
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_BRACK "]"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
+  ATTR
+    POUND "#"
+    BANG "!"
+    L_BRACK "["
+    META
+      UNSAFE_KW "unsafe"
+      L_PAREN "("
+      PATH
+        PATH
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "simple"
+          COLON2 "::"
+          PATH_SEGMENT
+            NAME_REF
+              IDENT "path"
+        COLON2 "::"
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "tt"
+      TOKEN_TREE
+        L_CURLY "{"
+        IDENT "a"
+        WHITESPACE " "
+        IDENT "b"
+        WHITESPACE " "
+        IDENT "c"
+        R_CURLY "}"
+      R_PAREN ")"
+    R_BRACK "]"
+  WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rs
new file mode 100644
index 0000000..57b7bb7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/0213_metas.rs
@@ -0,0 +1,20 @@
+#![simple_ident]
+#![simple::path]
+#![simple_ident_expr = ""]
+#![simple::path::Expr = ""]
+#![simple_ident_tt(a b c)]
+#![simple_ident_tt[a b c]]
+#![simple_ident_tt{a b c}]
+#![simple::path::tt(a b c)]
+#![simple::path::tt[a b c]]
+#![simple::path::tt{a b c}]
+#![unsafe(simple_ident)]
+#![unsafe(simple::path)]
+#![unsafe(simple_ident_expr = "")]
+#![unsafe(simple::path::Expr = "")]
+#![unsafe(simple_ident_tt(a b c))]
+#![unsafe(simple_ident_tt[a b c])]
+#![unsafe(simple_ident_tt{a b c})]
+#![unsafe(simple::path::tt(a b c))]
+#![unsafe(simple::path::tt[a b c])]
+#![unsafe(simple::path::tt{a b c})]
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
index 0ab16c3..8749417 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
@@ -13,7 +13,7 @@
 
 use base_db::Env;
 use indexmap::IndexSet;
-use paths::AbsPathBuf;
+use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::FxHashMap;
 use span::Span;
 use std::{
@@ -54,6 +54,7 @@
     ///
     /// Therefore, we just wrap the `ProcMacroProcessSrv` in a mutex here.
     process: Arc<Mutex<ProcMacroProcessSrv>>,
+    path: AbsPathBuf,
 }
 
 pub struct MacroDylib {
@@ -113,15 +114,22 @@
 impl ProcMacroServer {
     /// Spawns an external process as the proc macro server and returns a client connected to it.
     pub fn spawn(
-        process_path: AbsPathBuf,
+        process_path: &AbsPath,
         env: &FxHashMap<String, String>,
     ) -> io::Result<ProcMacroServer> {
         let process = ProcMacroProcessSrv::run(process_path, env)?;
-        Ok(ProcMacroServer { process: Arc::new(Mutex::new(process)) })
+        Ok(ProcMacroServer {
+            process: Arc::new(Mutex::new(process)),
+            path: process_path.to_owned(),
+        })
+    }
+
+    pub fn path(&self) -> &AbsPath {
+        &self.path
     }
 
     pub fn load_dylib(&self, dylib: MacroDylib) -> Result<Vec<ProcMacro>, ServerError> {
-        let _p = tracing::span!(tracing::Level::INFO, "ProcMacroClient::load_dylib").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "ProcMacroServer::load_dylib").entered();
         let macros =
             self.process.lock().unwrap_or_else(|e| e.into_inner()).find_proc_macros(&dylib.path)?;
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
index 35d48a1..dce086d 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
@@ -6,7 +6,7 @@
     sync::Arc,
 };
 
-use paths::{AbsPath, AbsPathBuf};
+use paths::AbsPath;
 use rustc_hash::FxHashMap;
 use stdx::JodChild;
 
@@ -28,11 +28,11 @@
 
 impl ProcMacroProcessSrv {
     pub(crate) fn run(
-        process_path: AbsPathBuf,
+        process_path: &AbsPath,
         env: &FxHashMap<String, String>,
     ) -> io::Result<ProcMacroProcessSrv> {
         let create_srv = |null_stderr| {
-            let mut process = Process::run(process_path.clone(), env, null_stderr)?;
+            let mut process = Process::run(process_path, env, null_stderr)?;
             let (stdin, stdout) = process.stdio().expect("couldn't access child stdio");
 
             io::Result::Ok(ProcMacroProcessSrv {
@@ -153,11 +153,11 @@
 
 impl Process {
     fn run(
-        path: AbsPathBuf,
+        path: &AbsPath,
         env: &FxHashMap<String, String>,
         null_stderr: bool,
     ) -> io::Result<Process> {
-        let child = JodChild(mk_child(&path, env, null_stderr)?);
+        let child = JodChild(mk_child(path, env, null_stderr)?);
         Ok(Process { child })
     }
 
diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml
index a87b67f..11a8e7a 100644
--- a/src/tools/rust-analyzer/crates/profile/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/profile/Cargo.toml
@@ -24,7 +24,7 @@
 perf-event = "=0.4.7"
 
 [target.'cfg(windows)'.dependencies]
-winapi = { version = "0.3.9", features = ["processthreadsapi", "psapi"] }
+windows-sys = { version = "0.52", features = ["Win32_System_Threading", "Win32_System_ProcessStatus"] }
 
 [features]
 cpu_profiler = []
diff --git a/src/tools/rust-analyzer/crates/profile/src/lib.rs b/src/tools/rust-analyzer/crates/profile/src/lib.rs
index a3fdb72..2ccb1cd 100644
--- a/src/tools/rust-analyzer/crates/profile/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/profile/src/lib.rs
@@ -26,7 +26,7 @@
 /// A wrapper around google_cpu_profiler.
 ///
 /// Usage:
-/// 1. Install gpref_tools (<https://github.com/gperftools/gperftools>), probably packaged with your Linux distro.
+/// 1. Install gperf_tools (<https://github.com/gperftools/gperftools>), probably packaged with your Linux distro.
 /// 2. Build with `cpu_profiler` feature.
 /// 3. Run the code, the *raw* output would be in the `./out.profile` file.
 /// 4. Install pprof for visualization (<https://github.com/google/pprof>).
diff --git a/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs b/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs
index f089c78..660afff 100644
--- a/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs
+++ b/src/tools/rust-analyzer/crates/profile/src/memory_usage.rs
@@ -37,8 +37,7 @@
                 // There doesn't seem to be an API for determining heap usage, so we try to
                 // approximate that by using the Commit Charge value.
 
-                use winapi::um::processthreadsapi::*;
-                use winapi::um::psapi::*;
+                use windows_sys::Win32::System::{Threading::*, ProcessStatus::*};
                 use std::mem::{MaybeUninit, size_of};
 
                 let proc = unsafe { GetCurrentProcess() };
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
index fbd423c..8e1f7fd 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
@@ -24,7 +24,7 @@
 
 use crate::{
     cfg::CfgFlag, utf8_stdout, CargoConfig, CargoFeatures, CargoWorkspace, InvocationLocation,
-    InvocationStrategy, Package, Sysroot, TargetKind,
+    InvocationStrategy, ManifestPath, Package, Sysroot, TargetKind,
 };
 
 /// Output of the build script and proc-macro building steps for a workspace.
@@ -63,9 +63,11 @@
     fn build_command(
         config: &CargoConfig,
         allowed_features: &FxHashSet<String>,
-        workspace_root: &AbsPathBuf,
+        manifest_path: &ManifestPath,
+        toolchain: Option<&Version>,
         sysroot: Option<&Sysroot>,
     ) -> io::Result<Command> {
+        const RUST_1_75: Version = Version::new(1, 75, 0);
         let mut cmd = match config.run_build_script_command.as_deref() {
             Some([program, args @ ..]) => {
                 let mut cmd = Command::new(program);
@@ -79,7 +81,7 @@
                 cmd.args(&config.extra_args);
 
                 cmd.arg("--manifest-path");
-                cmd.arg(workspace_root.join("Cargo.toml"));
+                cmd.arg(manifest_path.as_ref());
 
                 if let Some(target_dir) = &config.target_dir {
                     cmd.arg("--target-dir").arg(target_dir);
@@ -116,6 +118,14 @@
                     }
                 }
 
+                if manifest_path.is_rust_manifest() {
+                    cmd.arg("-Zscript");
+                }
+
+                if toolchain.map_or(false, |it| *it >= RUST_1_75) {
+                    cmd.arg("--keep-going");
+                }
+
                 cmd
             }
         };
@@ -138,11 +148,9 @@
         config: &CargoConfig,
         workspace: &CargoWorkspace,
         progress: &dyn Fn(String),
-        toolchain: &Option<Version>,
+        toolchain: Option<&Version>,
         sysroot: Option<&Sysroot>,
     ) -> io::Result<WorkspaceBuildScripts> {
-        const RUST_1_75: Version = Version::new(1, 75, 0);
-
         let current_dir = match &config.invocation_location {
             InvocationLocation::Root(root) if config.run_build_script_command.is_some() => {
                 root.as_path()
@@ -152,37 +160,14 @@
         .as_ref();
 
         let allowed_features = workspace.workspace_features();
-
-        match Self::run_per_ws(
-            Self::build_command(
-                config,
-                &allowed_features,
-                &workspace.workspace_root().to_path_buf(),
-                sysroot,
-            )?,
-            workspace,
-            current_dir,
-            progress,
-        ) {
-            Ok(WorkspaceBuildScripts { error: Some(error), .. })
-                if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_75) =>
-            {
-                // building build scripts failed, attempt to build with --keep-going so
-                // that we potentially get more build data
-                let mut cmd = Self::build_command(
-                    config,
-                    &allowed_features,
-                    &workspace.workspace_root().to_path_buf(),
-                    sysroot,
-                )?;
-
-                cmd.args(["--keep-going"]);
-                let mut res = Self::run_per_ws(cmd, workspace, current_dir, progress)?;
-                res.error = Some(error);
-                Ok(res)
-            }
-            res => res,
-        }
+        let cmd = Self::build_command(
+            config,
+            &allowed_features,
+            workspace.manifest_path(),
+            toolchain,
+            sysroot,
+        )?;
+        Self::run_per_ws(cmd, workspace, current_dir, progress)
     }
 
     /// Runs the build scripts by invoking the configured command *once*.
@@ -204,7 +189,14 @@
                 ))
             }
         };
-        let cmd = Self::build_command(config, &Default::default(), workspace_root, None)?;
+        let cmd = Self::build_command(
+            config,
+            &Default::default(),
+            // This is not gonna be used anyways, so just construct a dummy here
+            &ManifestPath::try_from(workspace_root.clone()).unwrap(),
+            None,
+            None,
+        )?;
         // NB: Cargo.toml could have been modified between `cargo metadata` and
         // `cargo check`. We shouldn't assume that package ids we see here are
         // exactly those from `config`.
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index ff7cf14..9955f26 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -32,6 +32,7 @@
     targets: Arena<TargetData>,
     workspace_root: AbsPathBuf,
     target_directory: AbsPathBuf,
+    manifest_path: ManifestPath,
 }
 
 impl ops::Index<Package> for CargoWorkspace {
@@ -306,7 +307,7 @@
             );
         }
         // The manifest is a rust file, so this means its a script manifest
-        if cargo_toml.extension().is_some_and(|ext| ext == "rs") {
+        if cargo_toml.is_rust_manifest() {
             // Deliberately don't set up RUSTC_BOOTSTRAP or a nightly override here, the user should
             // opt into it themselves.
             other_options.push("-Zscript".to_owned());
@@ -334,7 +335,7 @@
         .with_context(|| format!("Failed to run `{:?}`", meta.cargo_command()))
     }
 
-    pub fn new(mut meta: cargo_metadata::Metadata) -> CargoWorkspace {
+    pub fn new(mut meta: cargo_metadata::Metadata, manifest_path: ManifestPath) -> CargoWorkspace {
         let mut pkg_by_id = FxHashMap::default();
         let mut packages = Arena::default();
         let mut targets = Arena::default();
@@ -448,7 +449,7 @@
 
         let target_directory = AbsPathBuf::assert(meta.target_directory);
 
-        CargoWorkspace { packages, targets, workspace_root, target_directory }
+        CargoWorkspace { packages, targets, workspace_root, target_directory, manifest_path }
     }
 
     pub fn packages(&self) -> impl ExactSizeIterator<Item = Package> + '_ {
@@ -466,6 +467,10 @@
         &self.workspace_root
     }
 
+    pub fn manifest_path(&self) -> &ManifestPath {
+        &self.manifest_path
+    }
+
     pub fn target_directory(&self) -> &AbsPath {
         &self.target_directory
     }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/env.rs b/src/tools/rust-analyzer/crates/project-model/src/env.rs
index 762e01c..5520cda 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/env.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/env.rs
@@ -60,16 +60,19 @@
 }
 
 pub(crate) fn cargo_config_env(
-    cargo_toml: &ManifestPath,
+    manifest: &ManifestPath,
     extra_env: &FxHashMap<String, String>,
     sysroot: Option<&Sysroot>,
 ) -> FxHashMap<String, String> {
     let mut cargo_config = Sysroot::tool(sysroot, Tool::Cargo);
     cargo_config.envs(extra_env);
     cargo_config
-        .current_dir(cargo_toml.parent())
+        .current_dir(manifest.parent())
         .args(["-Z", "unstable-options", "config", "get", "env"])
         .env("RUSTC_BOOTSTRAP", "1");
+    if manifest.is_rust_manifest() {
+        cargo_config.arg("-Zscript");
+    }
     // if successful we receive `env.key.value = "value" per entry
     tracing::debug!("Discovering cargo config env by {:?}", cargo_config);
     utf8_stdout(cargo_config).map(parse_output_cargo_config_env).unwrap_or_default()
diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
index 7f3e35c..181c07f 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
@@ -52,13 +52,15 @@
     manifest_path::ManifestPath,
     project_json::{ProjectJson, ProjectJsonData},
     sysroot::Sysroot,
-    workspace::{FileLoader, PackageRoot, ProjectWorkspace},
+    workspace::{FileLoader, PackageRoot, ProjectWorkspace, ProjectWorkspaceKind},
 };
+pub use cargo_metadata::Metadata;
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub enum ProjectManifest {
     ProjectJson(ManifestPath),
     CargoToml(ManifestPath),
+    CargoScript(ManifestPath),
 }
 
 impl ProjectManifest {
@@ -71,7 +73,10 @@
         if path.file_name().unwrap_or_default() == "Cargo.toml" {
             return Ok(ProjectManifest::CargoToml(path));
         }
-        bail!("project root must point to Cargo.toml or rust-project.json: {path}");
+        if path.extension().unwrap_or_default() == "rs" {
+            return Ok(ProjectManifest::CargoScript(path));
+        }
+        bail!("project root must point to a Cargo.toml, rust-project.json or <script>.rs file: {path}");
     }
 
     pub fn discover_single(path: &AbsPath) -> anyhow::Result<ProjectManifest> {
@@ -146,15 +151,19 @@
         res.sort();
         res
     }
+
+    pub fn manifest_path(&self) -> &ManifestPath {
+        match self {
+            ProjectManifest::ProjectJson(it)
+            | ProjectManifest::CargoToml(it)
+            | ProjectManifest::CargoScript(it) => it,
+        }
+    }
 }
 
 impl fmt::Display for ProjectManifest {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            ProjectManifest::ProjectJson(it) | ProjectManifest::CargoToml(it) => {
-                fmt::Display::fmt(&it, f)
-            }
-        }
+        fmt::Display::fmt(self.manifest_path(), f)
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs b/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs
index d86e81e..2331c0c 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/manifest_path.rs
@@ -1,5 +1,5 @@
 //! See [`ManifestPath`].
-use std::{fmt, ops, path::Path};
+use std::{borrow::Borrow, fmt, ops};
 
 use paths::{AbsPath, AbsPathBuf};
 
@@ -38,6 +38,10 @@
     pub fn canonicalize(&self) -> ! {
         (**self).canonicalize()
     }
+
+    pub fn is_rust_manifest(&self) -> bool {
+        self.file.extension().map_or(false, |ext| ext == "rs")
+    }
 }
 
 impl fmt::Display for ManifestPath {
@@ -54,8 +58,14 @@
     }
 }
 
-impl AsRef<Path> for ManifestPath {
-    fn as_ref(&self) -> &Path {
+impl AsRef<AbsPath> for ManifestPath {
+    fn as_ref(&self) -> &AbsPath {
         self.file.as_ref()
     }
 }
+
+impl Borrow<AbsPath> for ManifestPath {
+    fn borrow(&self) -> &AbsPath {
+        self.file.borrow()
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
index fac6eb8..5bee446 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
@@ -56,6 +56,7 @@
 use span::Edition;
 
 use crate::cfg::CfgFlag;
+use crate::ManifestPath;
 
 /// Roots and crates that compose this Rust project.
 #[derive(Clone, Debug, Eq, PartialEq)]
@@ -65,6 +66,7 @@
     /// e.g. `path/to/sysroot/lib/rustlib/src/rust`
     pub(crate) sysroot_src: Option<AbsPathBuf>,
     project_root: AbsPathBuf,
+    manifest: Option<ManifestPath>,
     crates: Vec<Crate>,
 }
 
@@ -96,12 +98,17 @@
     /// * `base` - The path to the workspace root (i.e. the folder containing `rust-project.json`)
     /// * `data` - The parsed contents of `rust-project.json`, or project json that's passed via
     ///            configuration.
-    pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson {
+    pub fn new(
+        manifest: Option<ManifestPath>,
+        base: &AbsPath,
+        data: ProjectJsonData,
+    ) -> ProjectJson {
         let absolutize_on_base = |p| base.absolutize(p);
         ProjectJson {
             sysroot: data.sysroot.map(absolutize_on_base),
             sysroot_src: data.sysroot_src.map(absolutize_on_base),
             project_root: base.to_path_buf(),
+            manifest,
             crates: data
                 .crates
                 .into_iter()
@@ -159,6 +166,11 @@
     pub fn path(&self) -> &AbsPath {
         &self.project_root
     }
+
+    /// Returns the path to the project's manifest or root folder, if no manifest exists.
+    pub fn manifest_or_root(&self) -> &AbsPath {
+        self.manifest.as_ref().map_or(&self.project_root, |manifest| manifest.as_ref())
+    }
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index 1142d62..e6bbe6e 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -4,7 +4,7 @@
 //! but we can't process `.rlib` and need source code instead. The source code
 //! is typically installed with `rustup component add rust-src` command.
 
-use std::{env, fs, iter, ops, process::Command, sync::Arc};
+use std::{env, fs, ops, process::Command, sync::Arc};
 
 use anyhow::{format_err, Result};
 use base_db::CrateName;
@@ -58,13 +58,11 @@
     pub(crate) fn public_deps(&self) -> impl Iterator<Item = (CrateName, SysrootCrate, bool)> + '_ {
         // core is added as a dependency before std in order to
         // mimic rustcs dependency order
-        ["core", "alloc", "std"]
-            .into_iter()
-            .zip(iter::repeat(true))
-            .chain(iter::once(("test", false)))
-            .filter_map(move |(name, prelude)| {
+        [("core", true), ("alloc", false), ("std", true), ("test", false)].into_iter().filter_map(
+            move |(name, prelude)| {
                 Some((CrateName::new(name).unwrap(), self.by_name(name)?, prelude))
-            })
+            },
+        )
     }
 
     pub(crate) fn proc_macro(&self) -> Option<SysrootCrate> {
@@ -133,6 +131,24 @@
         }
     }
 
+    pub fn check_has_core(&self) -> Result<(), String> {
+        let Some(Ok(src_root)) = &self.src_root else { return Ok(()) };
+        let has_core = match &self.mode {
+            SysrootMode::Workspace(ws) => ws.packages().any(|p| ws[p].name == "core"),
+            SysrootMode::Stitched(stitched) => stitched.by_name("core").is_some(),
+        };
+        if !has_core {
+            let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
+                " (`RUST_SRC_PATH` might be incorrect, try unsetting it)"
+            } else {
+                " try running `rustup component add rust-src` to possible fix this"
+            };
+            Err(format!("could not find libcore in loaded sysroot at `{}`{var_note}", src_root,))
+        } else {
+            Ok(())
+        }
+    }
+
     pub fn num_packages(&self) -> usize {
         match &self.mode {
             SysrootMode::Workspace(ws) => ws.packages().count(),
@@ -349,7 +365,7 @@
                     .filter(|&package| RELEVANT_SYSROOT_CRATES.contains(&&*package.name))
                     .map(|package| package.id.clone())
                     .collect();
-                let cargo_workspace = CargoWorkspace::new(res);
+                let cargo_workspace = CargoWorkspace::new(res, sysroot_cargo_toml);
                 Some(Sysroot {
                     root: sysroot_dir.clone(),
                     src_root: Some(Ok(sysroot_src_dir.clone())),
@@ -368,7 +384,7 @@
                 .into_iter()
                 .map(|it| sysroot_src_dir.join(it))
                 .filter_map(|it| ManifestPath::try_from(it).ok())
-                .find(|it| fs::metadata(it).is_ok());
+                .find(|it| fs::metadata(it.as_ref()).is_ok());
 
             if let Some(root) = root {
                 stitched.crates.alloc(SysrootCrateData {
@@ -468,7 +484,7 @@
     let rustc_src = sysroot_path.join("lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml");
     let rustc_src = ManifestPath::try_from(rustc_src).ok()?;
     tracing::debug!("checking for rustc source code: {rustc_src}");
-    if fs::metadata(&rustc_src).is_ok() {
+    if fs::metadata(rustc_src.as_ref()).is_ok() {
         Some(rustc_src)
     } else {
         None
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index fd09dff..3d5a934 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -1,6 +1,7 @@
 use std::ops::Deref;
 
 use base_db::{CrateGraph, FileId, ProcMacroPaths};
+use cargo_metadata::Metadata;
 use cfg::{CfgAtom, CfgDiff};
 use expect_test::{expect_file, ExpectFile};
 use paths::{AbsPath, AbsPathBuf, Utf8Path, Utf8PathBuf};
@@ -9,8 +10,8 @@
 use triomphe::Arc;
 
 use crate::{
-    CargoWorkspace, CfgOverrides, ProjectJson, ProjectJsonData, ProjectWorkspace, Sysroot,
-    WorkspaceBuildScripts,
+    workspace::ProjectWorkspaceKind, CargoWorkspace, CfgOverrides, ManifestPath, ProjectJson,
+    ProjectJsonData, ProjectWorkspace, Sysroot, WorkspaceBuildScripts,
 };
 
 fn load_cargo(file: &str) -> (CrateGraph, ProcMacroPaths) {
@@ -21,18 +22,22 @@
     file: &str,
     cfg_overrides: CfgOverrides,
 ) -> (CrateGraph, ProcMacroPaths) {
-    let meta = get_test_json_file(file);
-    let cargo_workspace = CargoWorkspace::new(meta);
-    let project_workspace = ProjectWorkspace::Cargo {
-        cargo: cargo_workspace,
-        build_scripts: WorkspaceBuildScripts::default(),
-        sysroot: Err(None),
-        rustc: Err(None),
-        rustc_cfg: Vec::new(),
+    let meta: Metadata = get_test_json_file(file);
+    let manifest_path =
+        ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap();
+    let cargo_workspace = CargoWorkspace::new(meta, manifest_path);
+    let project_workspace = ProjectWorkspace {
+        kind: ProjectWorkspaceKind::Cargo {
+            cargo: cargo_workspace,
+            build_scripts: WorkspaceBuildScripts::default(),
+            rustc: Err(None),
+            cargo_config_extra_env: Default::default(),
+        },
         cfg_overrides,
+        sysroot: Err(None),
+        rustc_cfg: Vec::new(),
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
-        cargo_config_extra_env: Default::default(),
     };
     to_crate_graph(project_workspace)
 }
@@ -41,18 +46,22 @@
     file_map: &mut FxHashMap<AbsPathBuf, FileId>,
     file: &str,
 ) -> (CrateGraph, ProcMacroPaths) {
-    let meta = get_test_json_file(file);
-    let cargo_workspace = CargoWorkspace::new(meta);
-    let project_workspace = ProjectWorkspace::Cargo {
-        cargo: cargo_workspace,
-        build_scripts: WorkspaceBuildScripts::default(),
+    let meta: Metadata = get_test_json_file(file);
+    let manifest_path =
+        ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap();
+    let cargo_workspace = CargoWorkspace::new(meta, manifest_path);
+    let project_workspace = ProjectWorkspace {
+        kind: ProjectWorkspaceKind::Cargo {
+            cargo: cargo_workspace,
+            build_scripts: WorkspaceBuildScripts::default(),
+            rustc: Err(None),
+            cargo_config_extra_env: Default::default(),
+        },
         sysroot: Ok(get_fake_sysroot()),
-        rustc: Err(None),
         rustc_cfg: Vec::new(),
         cfg_overrides: Default::default(),
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
-        cargo_config_extra_env: Default::default(),
     };
     project_workspace.to_crate_graph(
         &mut {
@@ -69,8 +78,8 @@
     let data = get_test_json_file(file);
     let project = rooted_project_json(data);
     let sysroot = Ok(get_fake_sysroot());
-    let project_workspace = ProjectWorkspace::Json {
-        project,
+    let project_workspace = ProjectWorkspace {
+        kind: ProjectWorkspaceKind::Json(project),
         sysroot,
         rustc_cfg: Vec::new(),
         toolchain: None,
@@ -143,7 +152,7 @@
     replace_root(&mut root, true);
     let path = Utf8Path::new(&root);
     let base = AbsPath::assert(path);
-    ProjectJson::new(base, data)
+    ProjectJson::new(None, base, data)
 }
 
 fn to_crate_graph(project_workspace: ProjectWorkspace) -> (CrateGraph, ProcMacroPaths) {
@@ -268,9 +277,10 @@
         return;
     }
     let file_map = &mut FxHashMap::<AbsPathBuf, FileId>::default();
-    let meta = get_test_json_file("hello-world-metadata.json");
-
-    let cargo_workspace = CargoWorkspace::new(meta);
+    let meta: Metadata = get_test_json_file("hello-world-metadata.json");
+    let manifest_path =
+        ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap();
+    let cargo_workspace = CargoWorkspace::new(meta, manifest_path);
     let sysroot = Ok(Sysroot::discover(
         AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))),
         &Default::default(),
@@ -278,16 +288,18 @@
     )
     .unwrap());
 
-    let project_workspace = ProjectWorkspace::Cargo {
-        cargo: cargo_workspace,
-        build_scripts: WorkspaceBuildScripts::default(),
+    let project_workspace = ProjectWorkspace {
+        kind: ProjectWorkspaceKind::Cargo {
+            cargo: cargo_workspace,
+            build_scripts: WorkspaceBuildScripts::default(),
+            rustc: Err(None),
+            cargo_config_extra_env: Default::default(),
+        },
         sysroot,
-        rustc: Err(None),
         rustc_cfg: Vec::new(),
         cfg_overrides: Default::default(),
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
-        cargo_config_extra_env: Default::default(),
     };
     project_workspace.to_crate_graph(
         &mut {
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 98c5a02..8562144 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -4,7 +4,7 @@
 
 use std::{collections::VecDeque, fmt, fs, iter, sync};
 
-use anyhow::{format_err, Context};
+use anyhow::Context;
 use base_db::{
     CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Env, FileId,
     LangCrateOrigin, ProcMacroPaths, TargetLayoutLoadResult,
@@ -14,8 +14,8 @@
 use rustc_hash::{FxHashMap, FxHashSet};
 use semver::Version;
 use span::Edition;
-use stdx::always;
 use toolchain::Tool;
+use tracing::instrument;
 use triomphe::Arc;
 
 use crate::{
@@ -45,50 +45,39 @@
 }
 
 #[derive(Clone)]
-pub enum ProjectWorkspace {
+pub struct ProjectWorkspace {
+    pub kind: ProjectWorkspaceKind,
+    /// The sysroot loaded for this workspace.
+    pub sysroot: Result<Sysroot, Option<String>>,
+    /// Holds cfg flags for the current target. We get those by running
+    /// `rustc --print cfg`.
+    // FIXME: make this a per-crate map, as, eg, build.rs might have a
+    // different target.
+    pub rustc_cfg: Vec<CfgFlag>,
+    /// The toolchain version used by this workspace.
+    pub toolchain: Option<Version>,
+    /// The target data layout queried for workspace.
+    pub target_layout: TargetLayoutLoadResult,
+    /// A set of cfg overrides for this workspace.
+    pub cfg_overrides: CfgOverrides,
+}
+
+#[derive(Clone)]
+pub enum ProjectWorkspaceKind {
     /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
     Cargo {
         /// The workspace as returned by `cargo metadata`.
         cargo: CargoWorkspace,
         /// The build script results for the workspace.
         build_scripts: WorkspaceBuildScripts,
-        /// The sysroot loaded for this workspace.
-        sysroot: Result<Sysroot, Option<String>>,
         /// The rustc workspace loaded for this workspace. An `Err(None)` means loading has been
         /// disabled or was otherwise not requested.
         rustc: Result<Box<(CargoWorkspace, WorkspaceBuildScripts)>, Option<String>>,
-        /// Holds cfg flags for the current target. We get those by running
-        /// `rustc --print cfg`.
-        // FIXME: make this a per-crate map, as, eg, build.rs might have a
-        // different target.
-        rustc_cfg: Vec<CfgFlag>,
-        /// A set of cfg overrides for this workspace.
-        cfg_overrides: CfgOverrides,
-        /// The toolchain version used by this workspace.
-        toolchain: Option<Version>,
-        /// The target data layout queried for workspace.
-        target_layout: TargetLayoutLoadResult,
         /// Environment variables set in the `.cargo/config` file.
         cargo_config_extra_env: FxHashMap<String, String>,
     },
     /// Project workspace was manually specified using a `rust-project.json` file.
-    Json {
-        /// The loaded project json file.
-        project: ProjectJson,
-        /// The sysroot loaded for this workspace.
-        sysroot: Result<Sysroot, Option<String>>,
-        /// Holds cfg flags for the current target. We get those by running
-        /// `rustc --print cfg`.
-        // FIXME: make this a per-crate map, as, eg, build.rs might have a
-        // different target.
-        rustc_cfg: Vec<CfgFlag>,
-        /// The toolchain version used by this workspace.
-        toolchain: Option<Version>,
-        /// The target data layout queried for workspace.
-        target_layout: TargetLayoutLoadResult,
-        /// A set of cfg overrides for this workspace.
-        cfg_overrides: CfgOverrides,
-    },
+    Json(ProjectJson),
     // FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
     // That's not the end user experience we should strive for.
     // Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working.
@@ -101,38 +90,23 @@
     /// Backed by basic sysroot crates for basic completion and highlighting.
     DetachedFile {
         /// The file in question.
-        file: AbsPathBuf,
-        /// The sysroot loaded for this workspace.
-        sysroot: Result<Sysroot, Option<String>>,
-        /// Holds cfg flags for the current target. We get those by running
-        /// `rustc --print cfg`.
-        // FIXME: make this a per-crate map, as, eg, build.rs might have a
-        // different target.
-        rustc_cfg: Vec<CfgFlag>,
-        /// The toolchain version used by this workspace.
-        toolchain: Option<Version>,
-        /// The target data layout queried for workspace.
-        target_layout: TargetLayoutLoadResult,
-        /// A set of cfg overrides for the files.
-        cfg_overrides: CfgOverrides,
+        file: ManifestPath,
         /// Is this file a cargo script file?
-        cargo_script: Option<CargoWorkspace>,
+        cargo: Option<(CargoWorkspace, WorkspaceBuildScripts)>,
+        /// Environment variables set in the `.cargo/config` file.
+        cargo_config_extra_env: FxHashMap<String, String>,
     },
 }
 
 impl fmt::Debug for ProjectWorkspace {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         // Make sure this isn't too verbose.
-        match self {
-            ProjectWorkspace::Cargo {
+        let Self { kind, sysroot, rustc_cfg, toolchain, target_layout, cfg_overrides } = self;
+        match kind {
+            ProjectWorkspaceKind::Cargo {
                 cargo,
                 build_scripts: _,
-                sysroot,
                 rustc,
-                rustc_cfg,
-                cfg_overrides,
-                toolchain,
-                target_layout,
                 cargo_config_extra_env,
             } => f
                 .debug_struct("Cargo")
@@ -149,14 +123,7 @@
                 .field("data_layout", &target_layout)
                 .field("cargo_config_extra_env", &cargo_config_extra_env)
                 .finish(),
-            ProjectWorkspace::Json {
-                project,
-                sysroot,
-                rustc_cfg,
-                toolchain,
-                target_layout: data_layout,
-                cfg_overrides,
-            } => {
+            ProjectWorkspaceKind::Json(project) => {
                 let mut debug_struct = f.debug_struct("Json");
                 debug_struct.field("n_crates", &project.n_crates());
                 if let Ok(sysroot) = sysroot {
@@ -165,18 +132,14 @@
                 debug_struct
                     .field("n_rustc_cfg", &rustc_cfg.len())
                     .field("toolchain", &toolchain)
-                    .field("data_layout", &data_layout)
+                    .field("data_layout", &target_layout)
                     .field("n_cfg_overrides", &cfg_overrides.len());
                 debug_struct.finish()
             }
-            ProjectWorkspace::DetachedFile {
+            ProjectWorkspaceKind::DetachedFile {
                 file,
-                sysroot,
-                rustc_cfg,
-                toolchain,
-                target_layout,
-                cfg_overrides,
-                cargo_script,
+                cargo: cargo_script,
+                cargo_config_extra_env,
             } => f
                 .debug_struct("DetachedFiles")
                 .field("file", &file)
@@ -187,6 +150,7 @@
                 .field("toolchain", &toolchain)
                 .field("data_layout", &target_layout)
                 .field("n_cfg_overrides", &cfg_overrides.len())
+                .field("cargo_config_extra_env", &cargo_config_extra_env)
                 .finish(),
         }
     }
@@ -230,12 +194,13 @@
     ) -> anyhow::Result<ProjectWorkspace> {
         let res = match manifest {
             ProjectManifest::ProjectJson(project_json) => {
-                let file = fs::read_to_string(project_json)
+                let file = fs::read_to_string(project_json.as_ref())
                     .with_context(|| format!("Failed to read json file {project_json}"))?;
                 let data = serde_json::from_str(&file)
                     .with_context(|| format!("Failed to deserialize json file {project_json}"))?;
                 let project_location = project_json.parent().to_path_buf();
-                let project_json: ProjectJson = ProjectJson::new(&project_location, data);
+                let project_json: ProjectJson =
+                    ProjectJson::new(Some(project_json.clone()), &project_location, data);
                 ProjectWorkspace::load_inline(
                     project_json,
                     config.target.as_deref(),
@@ -243,6 +208,9 @@
                     &config.cfg_overrides,
                 )
             }
+            ProjectManifest::CargoScript(rust_file) => {
+                ProjectWorkspace::load_detached_file(rust_file, config)?
+            }
             ProjectManifest::CargoToml(cargo_toml) => {
                 let sysroot = match (&config.sysroot, &config.sysroot_src) {
                     (Some(RustLibSource::Path(path)), None) => {
@@ -299,7 +267,7 @@
                         progress,
                     ) {
                         Ok(meta) => {
-                            let workspace = CargoWorkspace::new(meta);
+                            let workspace = CargoWorkspace::new(meta, cargo_toml.clone());
                             let buildscripts = WorkspaceBuildScripts::rustc_crates(
                                 &workspace,
                                 cargo_toml.parent(),
@@ -355,22 +323,24 @@
                         "Failed to read Cargo metadata from Cargo.toml file {cargo_toml}, {toolchain:?}",
                     )
                 })?;
-                let cargo = CargoWorkspace::new(meta);
+                let cargo = CargoWorkspace::new(meta, cargo_toml.clone());
 
                 let cargo_config_extra_env =
                     cargo_config_env(cargo_toml, &config.extra_env, sysroot_ref);
-                ProjectWorkspace::Cargo {
-                    cargo,
-                    build_scripts: WorkspaceBuildScripts::default(),
+                ProjectWorkspace {
+                    kind: ProjectWorkspaceKind::Cargo {
+                        cargo,
+                        build_scripts: WorkspaceBuildScripts::default(),
+                        rustc,
+                        cargo_config_extra_env,
+                    },
                     sysroot,
-                    rustc,
                     rustc_cfg,
                     cfg_overrides,
                     toolchain,
                     target_layout: data_layout
                         .map(Arc::from)
                         .map_err(|it| Arc::from(it.to_string())),
-                    cargo_config_extra_env,
                 }
             }
         };
@@ -423,8 +393,8 @@
 
         let rustc_cfg = rustc_cfg::get(target, extra_env, cfg_config);
         let data_layout = target_data_layout::get(data_layout_config, target, extra_env);
-        ProjectWorkspace::Json {
-            project: project_json,
+        ProjectWorkspace {
+            kind: ProjectWorkspaceKind::Json(project_json),
             sysroot,
             rustc_cfg,
             toolchain,
@@ -433,82 +403,76 @@
         }
     }
 
+    pub fn load_detached_file(
+        detached_file: &ManifestPath,
+        config: &CargoConfig,
+    ) -> anyhow::Result<ProjectWorkspace> {
+        let dir = detached_file.parent();
+        let sysroot = match &config.sysroot {
+            Some(RustLibSource::Path(path)) => {
+                Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata)
+                    .map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}")))
+            }
+            Some(RustLibSource::Discover) => Sysroot::discover(
+                dir,
+                &config.extra_env,
+                config.sysroot_query_metadata,
+            )
+            .map_err(|e| {
+                Some(format!("Failed to find sysroot for {dir}. Is rust-src installed? {e}"))
+            }),
+            None => Err(None),
+        };
+
+        let sysroot_ref = sysroot.as_ref().ok();
+        let toolchain =
+            match get_toolchain_version(dir, sysroot_ref, Tool::Rustc, &config.extra_env, "rustc ")
+            {
+                Ok(it) => it,
+                Err(e) => {
+                    tracing::error!("{e}");
+                    None
+                }
+            };
+
+        let rustc_cfg = rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(sysroot_ref));
+        let data_layout = target_data_layout::get(
+            RustcDataLayoutConfig::Rustc(sysroot_ref),
+            None,
+            &config.extra_env,
+        );
+
+        let cargo_script =
+            CargoWorkspace::fetch_metadata(detached_file, dir, config, sysroot_ref, &|_| ())
+                .ok()
+                .map(|ws| {
+                    (
+                        CargoWorkspace::new(ws, detached_file.clone()),
+                        WorkspaceBuildScripts::default(),
+                    )
+                });
+
+        let cargo_config_extra_env =
+            cargo_config_env(detached_file, &config.extra_env, sysroot_ref);
+        Ok(ProjectWorkspace {
+            kind: ProjectWorkspaceKind::DetachedFile {
+                file: detached_file.to_owned(),
+                cargo: cargo_script,
+                cargo_config_extra_env,
+            },
+            sysroot,
+            rustc_cfg,
+            toolchain,
+            target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
+            cfg_overrides: config.cfg_overrides.clone(),
+        })
+    }
+
     pub fn load_detached_files(
-        detached_files: Vec<AbsPathBuf>,
+        detached_files: Vec<ManifestPath>,
         config: &CargoConfig,
     ) -> Vec<anyhow::Result<ProjectWorkspace>> {
-        detached_files
-            .into_iter()
-            .map(|detached_file| {
-                let dir = detached_file
-                    .parent()
-                    .ok_or_else(|| format_err!("detached file has no parent"))?;
-                let sysroot = match &config.sysroot {
-                    Some(RustLibSource::Path(path)) => {
-                        Sysroot::with_sysroot_dir(path.clone(), config.sysroot_query_metadata)
-                            .map_err(|e| Some(format!("Failed to find sysroot at {path}:{e}")))
-                    }
-                    Some(RustLibSource::Discover) => {
-                        Sysroot::discover(dir, &config.extra_env, config.sysroot_query_metadata)
-                            .map_err(|e| {
-                                Some(format!(
-                                    "Failed to find sysroot for {dir}. Is rust-src installed? {e}"
-                                ))
-                            })
-                    }
-                    None => Err(None),
-                };
-
-                let sysroot_ref = sysroot.as_ref().ok();
-                let toolchain = match get_toolchain_version(
-                    dir,
-                    sysroot_ref,
-                    Tool::Rustc,
-                    &config.extra_env,
-                    "rustc ",
-                ) {
-                    Ok(it) => it,
-                    Err(e) => {
-                        tracing::error!("{e}");
-                        None
-                    }
-                };
-
-                let rustc_cfg =
-                    rustc_cfg::get(None, &config.extra_env, RustcCfgConfig::Rustc(sysroot_ref));
-                let data_layout = target_data_layout::get(
-                    RustcDataLayoutConfig::Rustc(sysroot_ref),
-                    None,
-                    &config.extra_env,
-                );
-
-                let cargo_script = ManifestPath::try_from(detached_file.clone())
-                    .ok()
-                    .and_then(|file| {
-                        CargoWorkspace::fetch_metadata(
-                            &file,
-                            file.parent(),
-                            config,
-                            sysroot_ref,
-                            &|_| (),
-                        )
-                        .ok()
-                    })
-                    .map(CargoWorkspace::new);
-
-                Ok(ProjectWorkspace::DetachedFile {
-                    file: detached_file,
-                    sysroot,
-                    rustc_cfg,
-                    toolchain,
-                    target_layout: data_layout
-                        .map(Arc::from)
-                        .map_err(|it| Arc::from(it.to_string())),
-                    cfg_overrides: config.cfg_overrides.clone(),
-                    cargo_script,
-                })
-            })
-            .collect()
+        detached_files.into_iter().map(|file| Self::load_detached_file(&file, config)).collect()
     }
 
     /// Runs the build scripts for this [`ProjectWorkspace`].
@@ -517,27 +481,22 @@
         config: &CargoConfig,
         progress: &dyn Fn(String),
     ) -> anyhow::Result<WorkspaceBuildScripts> {
-        match self {
-            ProjectWorkspace::DetachedFile {
-                cargo_script: Some(cargo),
-                toolchain,
-                sysroot,
-                ..
-            }
-            | ProjectWorkspace::Cargo { cargo, toolchain, sysroot, .. } => {
+        match &self.kind {
+            ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. }
+            | ProjectWorkspaceKind::Cargo { cargo, .. } => {
                 WorkspaceBuildScripts::run_for_workspace(
                     config,
                     cargo,
                     progress,
-                    toolchain,
-                    sysroot.as_ref().ok(),
+                    self.toolchain.as_ref(),
+                    self.sysroot.as_ref().ok(),
                 )
                 .with_context(|| {
                     format!("Failed to run build scripts for {}", cargo.workspace_root())
                 })
             }
-            ProjectWorkspace::DetachedFile { cargo_script: None, .. }
-            | ProjectWorkspace::Json { .. } => Ok(WorkspaceBuildScripts::default()),
+            ProjectWorkspaceKind::DetachedFile { cargo: None, .. }
+            | ProjectWorkspaceKind::Json { .. } => Ok(WorkspaceBuildScripts::default()),
         }
     }
 
@@ -557,8 +516,8 @@
 
         let cargo_ws: Vec<_> = workspaces
             .iter()
-            .filter_map(|it| match it {
-                ProjectWorkspace::Cargo { cargo, .. } => Some(cargo),
+            .filter_map(|it| match &it.kind {
+                ProjectWorkspaceKind::Cargo { cargo, .. } => Some(cargo),
                 _ => None,
             })
             .collect();
@@ -572,8 +531,8 @@
 
         workspaces
             .iter()
-            .map(|it| match it {
-                ProjectWorkspace::Cargo { cargo, .. } => match outputs {
+            .map(|it| match &it.kind {
+                ProjectWorkspaceKind::Cargo { cargo, .. } => match outputs {
                     Ok(outputs) => Ok(outputs.next().unwrap()),
                     Err(e) => Err(e.clone()).with_context(|| {
                         format!("Failed to run build scripts for {}", cargo.workspace_root())
@@ -585,39 +544,33 @@
     }
 
     pub fn set_build_scripts(&mut self, bs: WorkspaceBuildScripts) {
-        match self {
-            ProjectWorkspace::Cargo { build_scripts, .. } => *build_scripts = bs,
-            _ => {
-                always!(bs == WorkspaceBuildScripts::default());
+        match &mut self.kind {
+            ProjectWorkspaceKind::Cargo { build_scripts, .. }
+            | ProjectWorkspaceKind::DetachedFile { cargo: Some((_, build_scripts)), .. } => {
+                *build_scripts = bs
             }
+            _ => assert_eq!(bs, WorkspaceBuildScripts::default()),
         }
     }
 
-    pub fn workspace_definition_path(&self) -> &AbsPath {
-        match self {
-            ProjectWorkspace::Cargo { cargo, .. } => cargo.workspace_root(),
-            ProjectWorkspace::Json { project, .. } => project.path(),
-            ProjectWorkspace::DetachedFile { file, .. } => file,
+    pub fn manifest_or_root(&self) -> &AbsPath {
+        match &self.kind {
+            ProjectWorkspaceKind::Cargo { cargo, .. } => cargo.manifest_path(),
+            ProjectWorkspaceKind::Json(project) => project.manifest_or_root(),
+            ProjectWorkspaceKind::DetachedFile { file, .. } => file,
         }
     }
 
     pub fn find_sysroot_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> {
-        match self {
-            ProjectWorkspace::Cargo { sysroot: Ok(sysroot), .. }
-            | ProjectWorkspace::Json { sysroot: Ok(sysroot), .. }
-            | ProjectWorkspace::DetachedFile { sysroot: Ok(sysroot), .. } => {
-                sysroot.discover_proc_macro_srv()
-            }
-            ProjectWorkspace::DetachedFile { .. } => {
-                Err(anyhow::format_err!("cannot find proc-macro server, no sysroot was found"))
-            }
-            ProjectWorkspace::Cargo { cargo, .. } => Err(anyhow::format_err!(
-                "cannot find proc-macro-srv, the workspace `{}` is missing a sysroot",
-                cargo.workspace_root()
+        match &self.sysroot {
+            Ok(sysroot) => sysroot.discover_proc_macro_srv(),
+            Err(None) => Err(anyhow::format_err!(
+                "cannot find proc-macro server, the workspace `{}` is missing a sysroot",
+                self.manifest_or_root()
             )),
-            ProjectWorkspace::Json { project, .. } => Err(anyhow::format_err!(
-                "cannot find proc-macro-srv, the workspace `{}` is missing a sysroot",
-                project.path()
+            Err(Some(e)) => Err(anyhow::format_err!(
+                "cannot find proc-macro server, the workspace `{}` is missing a sysroot: {e}",
+                self.manifest_or_root()
             )),
         }
     }
@@ -626,8 +579,8 @@
     /// The return type contains the path and whether or not
     /// the root is a member of the current workspace
     pub fn to_roots(&self) -> Vec<PackageRoot> {
-        let mk_sysroot = |sysroot: Result<_, _>| {
-            sysroot.into_iter().flat_map(move |sysroot: &Sysroot| {
+        let mk_sysroot = || {
+            self.sysroot.as_ref().into_iter().flat_map(move |sysroot: &Sysroot| {
                 let mut r = match sysroot.mode() {
                     SysrootMode::Workspace(ws) => ws
                         .packages()
@@ -661,15 +614,8 @@
                 r
             })
         };
-        match self {
-            ProjectWorkspace::Json {
-                project,
-                sysroot,
-                rustc_cfg: _,
-                toolchain: _,
-                target_layout: _,
-                cfg_overrides: _,
-            } => project
+        match &self.kind {
+            ProjectWorkspaceKind::Json(project) => project
                 .crates()
                 .map(|(_, krate)| PackageRoot {
                     is_local: krate.is_workspace_member,
@@ -678,17 +624,12 @@
                 })
                 .collect::<FxHashSet<_>>()
                 .into_iter()
-                .chain(mk_sysroot(sysroot.as_ref()))
+                .chain(mk_sysroot())
                 .collect::<Vec<_>>(),
-            ProjectWorkspace::Cargo {
+            ProjectWorkspaceKind::Cargo {
                 cargo,
-                sysroot,
                 rustc,
-                rustc_cfg: _,
-                cfg_overrides: _,
                 build_scripts,
-                toolchain: _,
-                target_layout: _,
                 cargo_config_extra_env: _,
             } => {
                 cargo
@@ -729,7 +670,7 @@
                         }
                         PackageRoot { is_local, include, exclude }
                     })
-                    .chain(mk_sysroot(sysroot.as_ref()))
+                    .chain(mk_sysroot())
                     .chain(rustc.iter().map(|a| a.as_ref()).flat_map(|(rustc, _)| {
                         rustc.packages().map(move |krate| PackageRoot {
                             is_local: false,
@@ -739,18 +680,21 @@
                     }))
                     .collect()
             }
-            ProjectWorkspace::DetachedFile { file, cargo_script, sysroot, .. } => {
+            ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, .. } => {
                 iter::once(PackageRoot {
                     is_local: true,
-                    include: vec![file.clone()],
+                    include: vec![file.as_ref().to_owned()],
                     exclude: Vec::new(),
                 })
-                .chain(cargo_script.iter().flat_map(|cargo| {
+                .chain(cargo_script.iter().flat_map(|(cargo, build_scripts)| {
                     cargo.packages().map(|pkg| {
                         let is_local = cargo[pkg].is_local;
                         let pkg_root = cargo[pkg].manifest.parent().to_path_buf();
 
                         let mut include = vec![pkg_root.clone()];
+                        let out_dir =
+                            build_scripts.get_output(pkg).and_then(|it| it.out_dir.clone());
+                        include.extend(out_dir);
 
                         // In case target's path is manually set in Cargo.toml to be
                         // outside the package root, add its parent as an extra include.
@@ -780,28 +724,28 @@
                         PackageRoot { is_local, include, exclude }
                     })
                 }))
-                .chain(mk_sysroot(sysroot.as_ref()))
+                .chain(mk_sysroot())
                 .collect()
             }
         }
     }
 
     pub fn n_packages(&self) -> usize {
-        match self {
-            ProjectWorkspace::Json { project, sysroot, .. } => {
-                let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages());
+        match &self.kind {
+            ProjectWorkspaceKind::Json(project) => {
+                let sysroot_package_len = self.sysroot.as_ref().map_or(0, |it| it.num_packages());
                 sysroot_package_len + project.n_crates()
             }
-            ProjectWorkspace::Cargo { cargo, sysroot, rustc, .. } => {
+            ProjectWorkspaceKind::Cargo { cargo, rustc, .. } => {
                 let rustc_package_len =
                     rustc.as_ref().map(|a| a.as_ref()).map_or(0, |(it, _)| it.packages().len());
-                let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages());
+                let sysroot_package_len = self.sysroot.as_ref().map_or(0, |it| it.num_packages());
                 cargo.packages().len() + sysroot_package_len + rustc_package_len
             }
-            ProjectWorkspace::DetachedFile { sysroot, cargo_script, .. } => {
-                let sysroot_package_len = sysroot.as_ref().map_or(0, |it| it.num_packages());
+            ProjectWorkspaceKind::DetachedFile { cargo: cargo_script, .. } => {
+                let sysroot_package_len = self.sysroot.as_ref().map_or(0, |it| it.num_packages());
                 sysroot_package_len
-                    + cargo_script.as_ref().map_or(1, |cargo| cargo.packages().len())
+                    + cargo_script.as_ref().map_or(1, |(cargo, _)| cargo.packages().len())
             }
         }
     }
@@ -813,15 +757,9 @@
     ) -> (CrateGraph, ProcMacroPaths) {
         let _p = tracing::span!(tracing::Level::INFO, "ProjectWorkspace::to_crate_graph").entered();
 
-        let ((mut crate_graph, proc_macros), sysroot) = match self {
-            ProjectWorkspace::Json {
-                project,
-                sysroot,
-                rustc_cfg,
-                toolchain: _,
-                target_layout: _,
-                cfg_overrides,
-            } => (
+        let Self { kind, sysroot, cfg_overrides, rustc_cfg, .. } = self;
+        let ((mut crate_graph, proc_macros), sysroot) = match kind {
+            ProjectWorkspaceKind::Json(project) => (
                 project_json_to_crate_graph(
                     rustc_cfg.clone(),
                     load,
@@ -832,15 +770,10 @@
                 ),
                 sysroot,
             ),
-            ProjectWorkspace::Cargo {
+            ProjectWorkspaceKind::Cargo {
                 cargo,
-                sysroot,
                 rustc,
-                rustc_cfg,
-                cfg_overrides,
                 build_scripts,
-                toolchain: _,
-                target_layout: _,
                 cargo_config_extra_env: _,
             } => (
                 cargo_to_crate_graph(
@@ -854,16 +787,8 @@
                 ),
                 sysroot,
             ),
-            ProjectWorkspace::DetachedFile {
-                file,
-                sysroot,
-                rustc_cfg,
-                toolchain: _,
-                target_layout: _,
-                cfg_overrides,
-                cargo_script,
-            } => (
-                if let Some(cargo) = cargo_script {
+            ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, .. } => (
+                if let Some((cargo, build_scripts)) = cargo_script {
                     cargo_to_crate_graph(
                         &mut |path| load(path),
                         None,
@@ -871,7 +796,7 @@
                         sysroot.as_ref().ok(),
                         rustc_cfg.clone(),
                         cfg_overrides,
-                        &WorkspaceBuildScripts::default(),
+                        build_scripts,
                     )
                 } else {
                     detached_file_to_crate_graph(
@@ -897,93 +822,60 @@
     }
 
     pub fn eq_ignore_build_data(&self, other: &Self) -> bool {
-        match (self, other) {
+        let Self { kind, sysroot, rustc_cfg, toolchain, target_layout, cfg_overrides, .. } = self;
+        let Self {
+            kind: o_kind,
+            sysroot: o_sysroot,
+            rustc_cfg: o_rustc_cfg,
+            toolchain: o_toolchain,
+            target_layout: o_target_layout,
+            cfg_overrides: o_cfg_overrides,
+            ..
+        } = other;
+        (match (kind, o_kind) {
             (
-                Self::Cargo {
+                ProjectWorkspaceKind::Cargo {
                     cargo,
-                    sysroot,
                     rustc,
-                    rustc_cfg,
-                    cfg_overrides,
-                    toolchain,
                     cargo_config_extra_env,
                     build_scripts: _,
-                    target_layout: _,
                 },
-                Self::Cargo {
+                ProjectWorkspaceKind::Cargo {
                     cargo: o_cargo,
-                    sysroot: o_sysroot,
                     rustc: o_rustc,
-                    rustc_cfg: o_rustc_cfg,
-                    cfg_overrides: o_cfg_overrides,
-                    toolchain: o_toolchain,
                     cargo_config_extra_env: o_cargo_config_extra_env,
                     build_scripts: _,
-                    target_layout: _,
                 },
             ) => {
                 cargo == o_cargo
                     && rustc == o_rustc
-                    && rustc_cfg == o_rustc_cfg
-                    && cfg_overrides == o_cfg_overrides
-                    && toolchain == o_toolchain
-                    && sysroot == o_sysroot
                     && cargo_config_extra_env == o_cargo_config_extra_env
             }
-            (
-                Self::Json {
-                    project,
-                    sysroot,
-                    rustc_cfg,
-                    toolchain,
-                    target_layout: _,
-                    cfg_overrides,
-                },
-                Self::Json {
-                    project: o_project,
-                    sysroot: o_sysroot,
-                    rustc_cfg: o_rustc_cfg,
-                    toolchain: o_toolchain,
-                    target_layout: _,
-                    cfg_overrides: o_cfg_overrides,
-                },
-            ) => {
+            (ProjectWorkspaceKind::Json(project), ProjectWorkspaceKind::Json(o_project)) => {
                 project == o_project
-                    && rustc_cfg == o_rustc_cfg
-                    && sysroot == o_sysroot
-                    && toolchain == o_toolchain
-                    && cfg_overrides == o_cfg_overrides
             }
             (
-                Self::DetachedFile {
+                ProjectWorkspaceKind::DetachedFile {
                     file,
-                    sysroot,
-                    rustc_cfg,
-                    cargo_script,
-                    toolchain,
-                    target_layout,
-                    cfg_overrides,
+                    cargo: Some((cargo_script, _)),
+                    cargo_config_extra_env,
                 },
-                Self::DetachedFile {
+                ProjectWorkspaceKind::DetachedFile {
                     file: o_file,
-                    sysroot: o_sysroot,
-                    rustc_cfg: o_rustc_cfg,
-                    cargo_script: o_cargo_script,
-                    toolchain: o_toolchain,
-                    target_layout: o_target_layout,
-                    cfg_overrides: o_cfg_overrides,
+                    cargo: Some((o_cargo_script, _)),
+                    cargo_config_extra_env: o_cargo_config_extra_env,
                 },
             ) => {
                 file == o_file
-                    && sysroot == o_sysroot
-                    && rustc_cfg == o_rustc_cfg
-                    && toolchain == o_toolchain
-                    && target_layout == o_target_layout
-                    && cfg_overrides == o_cfg_overrides
                     && cargo_script == o_cargo_script
+                    && cargo_config_extra_env == o_cargo_config_extra_env
             }
-            _ => false,
-        }
+            _ => return false,
+        }) && sysroot == o_sysroot
+            && rustc_cfg == o_rustc_cfg
+            && toolchain == o_toolchain
+            && target_layout == o_target_layout
+            && cfg_overrides == o_cfg_overrides
     }
 
     /// Returns `true` if the project workspace is [`Json`].
@@ -991,10 +883,11 @@
     /// [`Json`]: ProjectWorkspace::Json
     #[must_use]
     pub fn is_json(&self) -> bool {
-        matches!(self, Self::Json { .. })
+        matches!(self.kind, ProjectWorkspaceKind::Json { .. })
     }
 }
 
+#[instrument(skip_all)]
 fn project_json_to_crate_graph(
     rustc_cfg: Vec<CfgFlag>,
     load: FileLoader<'_>,
@@ -1294,11 +1187,11 @@
 fn detached_file_to_crate_graph(
     rustc_cfg: Vec<CfgFlag>,
     load: FileLoader<'_>,
-    detached_file: &AbsPathBuf,
+    detached_file: &ManifestPath,
     sysroot: Option<&Sysroot>,
     override_cfg: &CfgOverrides,
 ) -> (CrateGraph, ProcMacroPaths) {
-    let _p = tracing::span!(tracing::Level::INFO, "detached_files_to_crate_graph").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "detached_file_to_crate_graph").entered();
     let mut crate_graph = CrateGraph::default();
     let (public_deps, _libproc_macro) = match sysroot {
         Some(sysroot) => sysroot_to_crate_graph(&mut crate_graph, sysroot, rustc_cfg.clone(), load),
@@ -1520,7 +1413,7 @@
     /// Makes `from` depend on the public sysroot crates.
     fn add_to_crate_graph(&self, crate_graph: &mut CrateGraph, from: CrateId) {
         for (name, krate, prelude) in &self.deps {
-            add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude);
+            add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude, true);
         }
     }
 }
@@ -1573,7 +1466,7 @@
                         | LangCrateOrigin::Std => pub_deps.push((
                             CrateName::normalize_dashes(&lang_crate.to_string()),
                             cid,
-                            !matches!(lang_crate, LangCrateOrigin::Test),
+                            !matches!(lang_crate, LangCrateOrigin::Test | LangCrateOrigin::Alloc),
                         )),
                         LangCrateOrigin::ProcMacro => libproc_macro = Some(cid),
                         LangCrateOrigin::Other => (),
@@ -1674,12 +1567,20 @@
     name: CrateName,
     to: CrateId,
     prelude: bool,
+    sysroot: bool,
 ) {
-    add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude))
+    add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude, sysroot))
 }
 
 fn add_proc_macro_dep(crate_graph: &mut CrateGraph, from: CrateId, to: CrateId, prelude: bool) {
-    add_dep_with_prelude(crate_graph, from, CrateName::new("proc_macro").unwrap(), to, prelude);
+    add_dep_with_prelude(
+        crate_graph,
+        from,
+        CrateName::new("proc_macro").unwrap(),
+        to,
+        prelude,
+        true,
+    );
 }
 
 fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) {
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
index c2a2d6e..3401d7f 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
@@ -50,6 +50,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -111,6 +112,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -118,6 +120,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -179,6 +182,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -186,6 +190,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -247,6 +252,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -254,6 +260,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
index c2a2d6e..3401d7f 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
@@ -50,6 +50,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -111,6 +112,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -118,6 +120,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -179,6 +182,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -186,6 +190,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -247,6 +252,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -254,6 +260,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
index c291ffc..491568d 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
@@ -49,6 +49,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -109,6 +110,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -116,6 +118,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -176,6 +179,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -183,6 +187,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
@@ -243,6 +248,7 @@
                     "hello_world",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -250,6 +256,7 @@
                     "libc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Local {
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
index 80c9136..c123df8 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
@@ -30,6 +30,7 @@
                     "core",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Lang(
@@ -158,6 +159,7 @@
                     "std",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(1),
@@ -165,6 +167,7 @@
                     "core",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Lang(
@@ -233,6 +236,7 @@
                     "alloc",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(3),
@@ -240,6 +244,7 @@
                     "panic_unwind",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(2),
@@ -247,6 +252,7 @@
                     "panic_abort",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(1),
@@ -254,6 +260,7 @@
                     "core",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(5),
@@ -261,6 +268,7 @@
                     "profiler_builtins",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(9),
@@ -268,6 +276,7 @@
                     "unwind",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(7),
@@ -275,6 +284,7 @@
                     "std_detect",
                 ),
                 prelude: true,
+                sysroot: false,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(8),
@@ -282,6 +292,7 @@
                     "test",
                 ),
                 prelude: true,
+                sysroot: false,
             },
         ],
         origin: Lang(
@@ -409,13 +420,15 @@
                     "core",
                 ),
                 prelude: true,
+                sysroot: true,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(0),
                 name: CrateName(
                     "alloc",
                 ),
-                prelude: true,
+                prelude: false,
+                sysroot: true,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(6),
@@ -423,6 +436,7 @@
                     "std",
                 ),
                 prelude: true,
+                sysroot: true,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(8),
@@ -430,6 +444,7 @@
                     "test",
                 ),
                 prelude: false,
+                sysroot: true,
             },
             Dependency {
                 crate_id: Idx::<CrateData>(4),
@@ -437,6 +452,7 @@
                     "proc_macro",
                 ),
                 prelude: false,
+                sysroot: true,
             },
         ],
         origin: Local {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index cd33498..34b3e49 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -1,7 +1,8 @@
 [package]
 name = "rust-analyzer"
 version = "0.0.0"
-homepage = "https://github.com/rust-analyzer/rust-analyzer"
+homepage = "https://rust-analyzer.github.io/"
+repository = "https://github.com/rust-analyzer/rust-analyzer"
 description = "A language server for the Rust programming language"
 documentation = "https://rust-analyzer.github.io/manual.html"
 autobins = false
@@ -69,7 +70,7 @@
 paths.workspace = true
 
 [target.'cfg(windows)'.dependencies]
-winapi = "0.3.9"
+windows-sys = { version = "0.52", features = ["Win32_System_Threading"] }
 
 [target.'cfg(not(target_env = "msvc"))'.dependencies]
 jemallocator = { version = "0.5.0", package = "tikv-jemallocator", optional = true }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/build.rs b/src/tools/rust-analyzer/crates/rust-analyzer/build.rs
index 15935e2..72b741d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/build.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/build.rs
@@ -5,6 +5,7 @@
 fn main() {
     set_rerun();
     set_commit_info();
+    println!("cargo::rustc-check-cfg=cfg(rust_analyzer)");
     if option_env!("CFG_RELEASE").is_none() {
         println!("cargo:rustc-env=POKE_RA_DEVS=1");
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
index 78920f3..9daae91 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
@@ -259,9 +259,15 @@
         config.rediscover_workspaces();
     }
 
-    rust_analyzer::main_loop(config, connection)?;
+    // If the io_threads have an error, there's usually an error on the main
+    // loop too because the channels are closed. Ensure we report both errors.
+    match (rust_analyzer::main_loop(config, connection), io_threads.join()) {
+        (Err(loop_e), Err(join_e)) => anyhow::bail!("{loop_e}\n{join_e}"),
+        (Ok(_), Err(join_e)) => anyhow::bail!("{join_e}"),
+        (Err(loop_e), Ok(_)) => anyhow::bail!("{loop_e}"),
+        (Ok(_), Ok(_)) => {}
+    }
 
-    io_threads.join()?;
     tracing::info!("server did shut down");
     Ok(())
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
index 6a5f7b0..693a35b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -211,7 +211,7 @@
     use super::*;
 
     use ide::Edition;
-    use mbe::{syntax_node_to_token_tree, DummyTestSpanMap, DUMMY};
+    use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode, DummyTestSpanMap, DUMMY};
     use syntax::{
         ast::{self, AstNode},
         SmolStr,
@@ -221,7 +221,12 @@
         let cfg_expr = {
             let source_file = ast::SourceFile::parse(cfg, Edition::CURRENT).ok().unwrap();
             let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
-            let tt = syntax_node_to_token_tree(tt.syntax(), &DummyTestSpanMap, DUMMY);
+            let tt = syntax_node_to_token_tree(
+                tt.syntax(),
+                &DummyTestSpanMap,
+                DUMMY,
+                DocCommentDesugarMode::Mbe,
+            );
             CfgExpr::parse(&tt)
         };
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index a1eea88..5208aa9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -986,6 +986,7 @@
                     prefer_no_std: false,
                     prefer_prelude: true,
                     style_lints: false,
+                    term_search_fuel: 400,
                 },
                 ide::AssistResolveStrategy::All,
                 file_id,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
index 79d6226..d5eac49 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -13,6 +13,17 @@
 
 impl flags::Diagnostics {
     pub fn run(self) -> anyhow::Result<()> {
+        const STACK_SIZE: usize = 1024 * 1024 * 8;
+
+        let handle = stdx::thread::Builder::new(stdx::thread::ThreadIntent::LatencySensitive)
+            .name("BIG_STACK_THREAD".into())
+            .stack_size(STACK_SIZE)
+            .spawn(|| self.run_())
+            .unwrap();
+
+        handle.join()
+    }
+    fn run_(self) -> anyhow::Result<()> {
         let cargo_config =
             CargoConfig { sysroot: Some(RustLibSource::Discover), ..Default::default() };
         let with_proc_macro_server = if let Some(p) = &self.proc_macro_srv {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs
index ead4d70..ed048aa 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/parse.rs
@@ -6,7 +6,7 @@
 
 impl flags::Parse {
     pub fn run(self) -> anyhow::Result<()> {
-        let _p = tracing::span!(tracing::Level::INFO, "parsing").entered();
+        let _p = tracing::span!(tracing::Level::INFO, "flags::Parse::run").entered();
         let text = read_stdin()?;
         let file = SourceFile::parse(&text, Edition::CURRENT).tree();
         if !self.no_dump {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs
index 6964977..8b143da 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs
@@ -96,7 +96,7 @@
     }
 
     fn set_value(&mut self, value: f32) {
-        self.curr = f32::max(0.0, f32::min(1.0, value));
+        self.curr = value.clamp(0.0, 1.0);
     }
 
     fn clear(&mut self) {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
index 2f9394d..85f964b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -10,7 +10,10 @@
 use itertools::Either;
 use profile::StopWatch;
 use project_model::target_data_layout::RustcDataLayoutConfig;
-use project_model::{target_data_layout, CargoConfig, ProjectWorkspace, RustLibSource, Sysroot};
+use project_model::{
+    target_data_layout, CargoConfig, ManifestPath, ProjectWorkspace, ProjectWorkspaceKind,
+    RustLibSource, Sysroot,
+};
 
 use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice};
 use rustc_hash::FxHashMap;
@@ -75,14 +78,17 @@
             &cargo_config.extra_env,
         );
 
-        let workspace = ProjectWorkspace::DetachedFile {
-            file: tmp_file,
+        let workspace = ProjectWorkspace {
+            kind: ProjectWorkspaceKind::DetachedFile {
+                file: ManifestPath::try_from(tmp_file).unwrap(),
+                cargo: None,
+                cargo_config_extra_env: Default::default(),
+            },
             sysroot,
             rustc_cfg: vec![],
             toolchain: None,
             target_layout: data_layout.map(Arc::from).map_err(|it| Arc::from(it.to_string())),
             cfg_overrides: Default::default(),
-            cargo_script: None,
         };
         let load_cargo_config = LoadCargoConfig {
             load_out_dirs_from_check: false,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index e956791..6c332ae 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -230,7 +230,7 @@
         /// If `$saved_file` is part of the command, rust-analyzer will pass
         /// the absolute path of the saved file to the provided command. This is
         /// intended to be used with non-Cargo build systems.
-        /// Note that `$saved_file` is experimental and may be removed in the futureg.
+        /// Note that `$saved_file` is experimental and may be removed in the future.
         ///
         /// An example command would be:
         ///
@@ -315,8 +315,10 @@
         /// How to render the size information in a memory layout hover.
         hover_memoryLayout_size: Option<MemoryLayoutHoverRenderKindDef> = Some(MemoryLayoutHoverRenderKindDef::Both),
 
-        /// How many fields of a struct to display when hovering a struct.
-        hover_show_structFields: Option<usize> = None,
+        /// How many variants of an enum to display when hovering on. Show none if empty.
+        hover_show_enumVariants: Option<usize> = Some(5),
+        /// How many fields of a struct, variant or union to display when hovering on. Show none if empty.
+        hover_show_fields: Option<usize> = Some(5),
         /// How many associated items of a trait to display when hovering a trait.
         hover_show_traitAssocItems: Option<usize> = None,
 
@@ -356,7 +358,8 @@
         /// of projects.
         ///
         /// Elements must be paths pointing to `Cargo.toml`,
-        /// `rust-project.json`, or JSON objects in `rust-project.json` format.
+        /// `rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON
+        /// objects in `rust-project.json` format.
         linkedProjects: Vec<ManifestOrProjectJson> = vec![],
 
         /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.
@@ -451,6 +454,9 @@
     /// Local configurations can be overridden for every crate by placing a `rust-analyzer.toml` on crate root.
     /// A config is searched for by traversing a "config tree" in a bottom up fashion. It is chosen by the nearest first principle.
     local: struct LocalDefaultConfigData <- LocalConfigInput ->  {
+        /// Term search fuel in "units of work" for assists (Defaults to 400).
+        assist_termSearch_fuel: usize = 400,
+
         /// Toggles the additional completions that automatically add imports when completed.
         /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
         completion_autoimport_enable: bool       = true,
@@ -512,6 +518,8 @@
         }"#).unwrap(),
         /// Whether to enable term search based snippets like `Some(foo.bar().baz())`.
         completion_termSearch_enable: bool = false,
+        /// Term search fuel in "units of work" for autocompletion (Defaults to 200).
+        completion_termSearch_fuel: usize = 200,
 
         /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
         highlightRelated_breakPoints_enable: bool = true,
@@ -1012,6 +1020,7 @@
             prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
             assist_emit_must_use: self.assist_emitMustUse().to_owned(),
             prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
+            term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64,
         }
     }
 
@@ -1045,6 +1054,7 @@
             snippets: self.snippets.clone().to_vec(),
             limit: self.completion_limit(source_root).to_owned(),
             enable_term_search: self.completion_termSearch_enable(source_root).to_owned(),
+            term_search_fuel: self.completion_termSearch_fuel(source_root).to_owned() as u64,
             prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
         }
     }
@@ -1064,6 +1074,7 @@
             prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
             prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
             style_lints: self.diagnostics_styleLints_enable().to_owned(),
+            term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64,
         }
     }
     pub fn expand_proc_attr_macros(&self) -> bool {
@@ -1125,7 +1136,8 @@
             },
             keywords: self.hover_documentation_keywords_enable().to_owned(),
             max_trait_assoc_items_count: self.hover_show_traitAssocItems().to_owned(),
-            max_struct_field_count: self.hover_show_structFields().to_owned(),
+            max_fields_count: self.hover_show_fields().to_owned(),
+            max_enum_variants_count: self.hover_show_enumVariants().to_owned(),
         }
     }
 
@@ -1301,12 +1313,9 @@
                     self.files_excludeDirs().iter().map(|p| self.root_path.join(p)).collect();
                 self.discovered_projects
                     .iter()
-                    .filter(
-                        |(ProjectManifest::ProjectJson(path)
-                         | ProjectManifest::CargoToml(path))| {
-                            !exclude_dirs.iter().any(|p| path.starts_with(p))
-                        },
-                    )
+                    .filter(|project| {
+                        !exclude_dirs.iter().any(|p| project.manifest_path().starts_with(p))
+                    })
                     .cloned()
                     .map(LinkedProject::from)
                     .collect()
@@ -1322,7 +1331,7 @@
                             .map(Into::into)
                     }
                     ManifestOrProjectJson::ProjectJson(it) => {
-                        Some(ProjectJson::new(&self.root_path, it.clone()).into())
+                        Some(ProjectJson::new(None, &self.root_path, it.clone()).into())
                     }
                 })
                 .collect(),
@@ -1775,7 +1784,7 @@
 
     pub fn lens(&self) -> LensConfig {
         LensConfig {
-            run: *self.lens_run_enable(),
+            run: *self.lens_enable() && *self.lens_run_enable(),
             debug: *self.lens_enable() && *self.lens_debug_enable(),
             interpret: *self.lens_enable() && *self.lens_run_enable() && *self.interpret_tests(),
             implementations: *self.lens_enable() && *self.lens_implementations_enable(),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
index 7adaef4..cf3b8d3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
@@ -95,45 +95,8 @@
         self
     }
 
-    /// Dispatches a non-latency-sensitive request onto the thread pool
-    /// without retrying it if it panics.
-    pub(crate) fn on_no_retry<R>(
-        &mut self,
-        f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
-    ) -> &mut Self
-    where
-        R: lsp_types::request::Request + 'static,
-        R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
-        R::Result: Serialize,
-    {
-        let (req, params, panic_context) = match self.parse::<R>() {
-            Some(it) => it,
-            None => return self,
-        };
-
-        self.global_state.task_pool.handle.spawn(ThreadIntent::Worker, {
-            let world = self.global_state.snapshot();
-            move || {
-                let result = panic::catch_unwind(move || {
-                    let _pctx = stdx::panic_context::enter(panic_context);
-                    f(world, params)
-                });
-                match thread_result_to_response::<R>(req.id.clone(), result) {
-                    Ok(response) => Task::Response(response),
-                    Err(_) => Task::Response(lsp_server::Response::new_err(
-                        req.id,
-                        lsp_server::ErrorCode::ContentModified as i32,
-                        "content modified".to_owned(),
-                    )),
-                }
-            }
-        });
-
-        self
-    }
-
     /// Dispatches a non-latency-sensitive request onto the thread pool.
-    pub(crate) fn on<R>(
+    pub(crate) fn on<const ALLOW_RETRYING: bool, R>(
         &mut self,
         f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
     ) -> &mut Self
@@ -142,11 +105,11 @@
         R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
         R::Result: Serialize,
     {
-        self.on_with_thread_intent::<true, R>(ThreadIntent::Worker, f)
+        self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::Worker, f)
     }
 
     /// Dispatches a latency-sensitive request onto the thread pool.
-    pub(crate) fn on_latency_sensitive<R>(
+    pub(crate) fn on_latency_sensitive<const ALLOW_RETRYING: bool, R>(
         &mut self,
         f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
     ) -> &mut Self
@@ -155,7 +118,7 @@
         R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
         R::Result: Serialize,
     {
-        self.on_with_thread_intent::<true, R>(ThreadIntent::LatencySensitive, f)
+        self.on_with_thread_intent::<true, ALLOW_RETRYING, R>(ThreadIntent::LatencySensitive, f)
     }
 
     /// Formatting requests should never block on waiting a for task thread to open up, editors will wait
@@ -170,7 +133,7 @@
         R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
         R::Result: Serialize,
     {
-        self.on_with_thread_intent::<false, R>(ThreadIntent::LatencySensitive, f)
+        self.on_with_thread_intent::<false, false, R>(ThreadIntent::LatencySensitive, f)
     }
 
     pub(crate) fn finish(&mut self) {
@@ -185,7 +148,7 @@
         }
     }
 
-    fn on_with_thread_intent<const MAIN_POOL: bool, R>(
+    fn on_with_thread_intent<const MAIN_POOL: bool, const ALLOW_RETRYING: bool, R>(
         &mut self,
         intent: ThreadIntent,
         f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result<R::Result>,
@@ -215,7 +178,12 @@
             });
             match thread_result_to_response::<R>(req.id.clone(), result) {
                 Ok(response) => Task::Response(response),
-                Err(_) => Task::Retry(req),
+                Err(_cancelled) if ALLOW_RETRYING => Task::Retry(req),
+                Err(_cancelled) => Task::Response(lsp_server::Response::new_err(
+                    req.id,
+                    lsp_server::ErrorCode::ContentModified as i32,
+                    "content modified".to_owned(),
+                )),
             }
         });
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index e9bca19..f64e661 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -3,7 +3,7 @@
 //!
 //! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
 
-use std::{collections::hash_map::Entry, time::Instant};
+use std::time::Instant;
 
 use crossbeam_channel::{unbounded, Receiver, Sender};
 use flycheck::FlycheckHandle;
@@ -18,10 +18,14 @@
     RwLockWriteGuard,
 };
 use proc_macro_api::ProcMacroServer;
-use project_model::{CargoWorkspace, ProjectWorkspace, Target, WorkspaceBuildScripts};
+use project_model::{
+    CargoWorkspace, ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, Target,
+    WorkspaceBuildScripts,
+};
 use rustc_hash::{FxHashMap, FxHashSet};
+use tracing::{span, Level};
 use triomphe::Arc;
-use vfs::{AnchoredPathBuf, ChangedFile, Vfs};
+use vfs::{AnchoredPathBuf, Vfs};
 
 use crate::{
     config::{Config, ConfigError},
@@ -125,7 +129,7 @@
     /// to invalidate any salsa caches.
     pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
     pub(crate) crate_graph_file_dependencies: FxHashSet<vfs::VfsPath>,
-    pub(crate) detached_files: FxHashSet<vfs::AbsPathBuf>,
+    pub(crate) detached_files: FxHashSet<ManifestPath>,
 
     // op queues
     pub(crate) fetch_workspaces_queue:
@@ -249,9 +253,7 @@
     }
 
     pub(crate) fn process_changes(&mut self) -> bool {
-        let _p = tracing::span!(tracing::Level::INFO, "GlobalState::process_changes").entered();
-
-        let mut file_changes = FxHashMap::<_, (bool, ChangedFile)>::default();
+        let _p = span!(Level::INFO, "GlobalState::process_changes").entered();
         let (change, modified_rust_files, workspace_structure_change) = {
             let mut change = ChangeWithProcMacros::new();
             let mut guard = self.vfs.write();
@@ -263,58 +265,16 @@
             // downgrade to read lock to allow more readers while we are normalizing text
             let guard = RwLockWriteGuard::downgrade_to_upgradable(guard);
             let vfs: &Vfs = &guard.0;
-            // We need to fix up the changed events a bit. If we have a create or modify for a file
-            // id that is followed by a delete we actually skip observing the file text from the
-            // earlier event, to avoid problems later on.
-            for changed_file in changed_files {
-                use vfs::Change::*;
-                match file_changes.entry(changed_file.file_id) {
-                    Entry::Occupied(mut o) => {
-                        let (just_created, change) = o.get_mut();
-                        match (&mut change.change, just_created, changed_file.change) {
-                            // latter `Delete` wins
-                            (change, _, Delete) => *change = Delete,
-                            // merge `Create` with `Create` or `Modify`
-                            (Create(prev), _, Create(new) | Modify(new)) => *prev = new,
-                            // collapse identical `Modify`es
-                            (Modify(prev), _, Modify(new)) => *prev = new,
-                            // equivalent to `Modify`
-                            (change @ Delete, just_created, Create(new)) => {
-                                *change = Modify(new);
-                                *just_created = true;
-                            }
-                            // shouldn't occur, but collapse into `Create`
-                            (change @ Delete, just_created, Modify(new)) => {
-                                *change = Create(new);
-                                *just_created = true;
-                            }
-                            // shouldn't occur, but keep the Create
-                            (prev @ Modify(_), _, new @ Create(_)) => *prev = new,
-                        }
-                    }
-                    Entry::Vacant(v) => {
-                        _ = v.insert((matches!(&changed_file.change, Create(_)), changed_file))
-                    }
-                }
-            }
-
-            let changed_files: Vec<_> = file_changes
-                .into_iter()
-                .filter(|(_, (just_created, change))| {
-                    !(*just_created && matches!(change.change, vfs::Change::Delete))
-                })
-                .map(|(file_id, (_, change))| vfs::ChangedFile { file_id, ..change })
-                .collect();
 
             let mut workspace_structure_change = None;
             // A file was added or deleted
             let mut has_structure_changes = false;
             let mut bytes = vec![];
             let mut modified_rust_files = vec![];
-            for file in changed_files {
+            for file in changed_files.into_values() {
                 let vfs_path = vfs.file_path(file.file_id);
                 if let Some(path) = vfs_path.as_path() {
-                    has_structure_changes = file.is_created_or_deleted();
+                    has_structure_changes |= file.is_created_or_deleted();
 
                     if file.is_modified() && path.extension() == Some("rs") {
                         modified_rust_files.push(file.file_id);
@@ -334,16 +294,17 @@
                     self.diagnostics.clear_native_for(file.file_id);
                 }
 
-                let text = if let vfs::Change::Create(v) | vfs::Change::Modify(v) = file.change {
-                    String::from_utf8(v).ok().map(|text| {
-                        // FIXME: Consider doing normalization in the `vfs` instead? That allows
-                        // getting rid of some locking
-                        let (text, line_endings) = LineEndings::normalize(text);
-                        (text, line_endings)
-                    })
-                } else {
-                    None
-                };
+                let text =
+                    if let vfs::Change::Create(v, _) | vfs::Change::Modify(v, _) = file.change {
+                        String::from_utf8(v).ok().map(|text| {
+                            // FIXME: Consider doing normalization in the `vfs` instead? That allows
+                            // getting rid of some locking
+                            let (text, line_endings) = LineEndings::normalize(text);
+                            (text, line_endings)
+                        })
+                    } else {
+                        None
+                    };
                 // delay `line_endings_map` changes until we are done normalizing the text
                 // this allows delaying the re-acquisition of the write lock
                 bytes.push((file.file_id, text));
@@ -363,6 +324,7 @@
             (change, modified_rust_files, workspace_structure_change)
         };
 
+        let _p = span!(Level::INFO, "GlobalState::process_changes/apply_change").entered();
         self.analysis_host.apply_change(change);
 
         {
@@ -376,6 +338,9 @@
             // but something's going wrong with the source root business when we add a new local
             // crate see https://github.com/rust-lang/rust-analyzer/issues/13029
             if let Some((path, force_crate_graph_reload)) = workspace_structure_change {
+                let _p = span!(Level::INFO, "GlobalState::process_changes/ws_structure_change")
+                    .entered();
+
                 self.fetch_workspaces_queue.request_op(
                     format!("workspace vfs file change: {path}"),
                     force_crate_graph_reload,
@@ -492,6 +457,10 @@
         Ok(res)
     }
 
+    pub(crate) fn file_version(&self, file_id: FileId) -> Option<i32> {
+        Some(self.mem_docs.get(self.vfs_read().file_path(file_id))?.version)
+    }
+
     pub(crate) fn url_file_version(&self, url: &Url) -> Option<i32> {
         let path = from_proto::vfs_path(url).ok()?;
         Some(self.mem_docs.get(&path)?.version)
@@ -516,12 +485,13 @@
         let file_id = self.analysis.crate_root(crate_id).ok()?;
         let path = self.vfs_read().file_path(file_id).clone();
         let path = path.as_path()?;
-        self.workspaces.iter().find_map(|ws| match ws {
-            ProjectWorkspace::Cargo { cargo, .. } => {
+        self.workspaces.iter().find_map(|ws| match &ws.kind {
+            ProjectWorkspaceKind::Cargo { cargo, .. }
+            | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. } => {
                 cargo.target_by_root(path).map(|it| (cargo, it))
             }
-            ProjectWorkspace::Json { .. } => None,
-            ProjectWorkspace::DetachedFile { .. } => None,
+            ProjectWorkspaceKind::Json { .. } => None,
+            ProjectWorkspaceKind::DetachedFile { .. } => None,
         })
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
index 4b8c3d0..9d30063 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
@@ -289,17 +289,19 @@
 
             // Find all workspaces that have at least one target containing the saved file
             let workspace_ids = world.workspaces.iter().enumerate().filter_map(|(idx, ws)| {
-                let package = match ws {
-                    project_model::ProjectWorkspace::Cargo { cargo, .. } => {
-                        cargo.packages().find_map(|pkg| {
-                            let has_target_with_root = cargo[pkg]
-                                .targets
-                                .iter()
-                                .any(|&it| crate_root_paths.contains(&cargo[it].root.as_path()));
-                            has_target_with_root.then(|| cargo[pkg].name.clone())
-                        })
-                    }
-                    project_model::ProjectWorkspace::Json { project, .. } => {
+                let package = match &ws.kind {
+                    project_model::ProjectWorkspaceKind::Cargo { cargo, .. }
+                    | project_model::ProjectWorkspaceKind::DetachedFile {
+                        cargo: Some((cargo, _)),
+                        ..
+                    } => cargo.packages().find_map(|pkg| {
+                        let has_target_with_root = cargo[pkg]
+                            .targets
+                            .iter()
+                            .any(|&it| crate_root_paths.contains(&cargo[it].root.as_path()));
+                        has_target_with_root.then(|| cargo[pkg].name.clone())
+                    }),
+                    project_model::ProjectWorkspaceKind::Json(project) => {
                         if !project.crates().any(|(_, krate)| {
                             crate_root_paths.contains(&krate.root_module.as_path())
                         }) {
@@ -307,8 +309,7 @@
                         }
                         None
                     }
-                    // FIXME
-                    project_model::ProjectWorkspace::DetachedFile { .. } => return None,
+                    project_model::ProjectWorkspaceKind::DetachedFile { .. } => return None,
                 };
                 Some((idx, package))
             });
@@ -348,7 +349,7 @@
 }
 
 pub(crate) fn handle_cancel_flycheck(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
-    let _p = tracing::span!(tracing::Level::INFO, "handle_stop_flycheck").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "handle_cancel_flycheck").entered();
     state.flycheck.iter().for_each(|flycheck| flycheck.cancel());
     Ok(())
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index cf97d7d..5ee0456 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -27,7 +27,7 @@
     SemanticTokensResult, SymbolInformation, SymbolTag, TextDocumentIdentifier, Url, WorkspaceEdit,
 };
 use paths::Utf8PathBuf;
-use project_model::{ManifestPath, ProjectWorkspace, TargetKind};
+use project_model::{ManifestPath, ProjectWorkspaceKind, TargetKind};
 use serde_json::json;
 use stdx::{format_to, never};
 use syntax::{algo, ast, AstNode, TextRange, TextSize};
@@ -99,10 +99,7 @@
         format_to!(
             buf,
             "Workspace root folders: {:?}",
-            snap.workspaces
-                .iter()
-                .map(|ws| ws.workspace_definition_path())
-                .collect::<Vec<&AbsPath>>()
+            snap.workspaces.iter().map(|ws| ws.manifest_or_root()).collect::<Vec<&AbsPath>>()
         );
     }
     buf.push_str("\nAnalysis:\n");
@@ -228,7 +225,7 @@
     };
     let mut handles = vec![];
     for ws in &*state.workspaces {
-        if let ProjectWorkspace::Cargo { cargo, .. } = ws {
+        if let ProjectWorkspaceKind::Cargo { cargo, .. } = &ws.kind {
             let handle = flycheck::CargoTestHandle::new(
                 test_path,
                 state.config.cargo_test_options(),
@@ -769,8 +766,11 @@
             let links: Vec<LocationLink> = snap
                 .workspaces
                 .iter()
-                .filter_map(|ws| match ws {
-                    ProjectWorkspace::Cargo { cargo, .. } => cargo.parent_manifests(&manifest_path),
+                .filter_map(|ws| match &ws.kind {
+                    ProjectWorkspaceKind::Cargo { cargo, .. }
+                    | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. } => {
+                        cargo.parent_manifests(&manifest_path)
+                    }
                     _ => None,
                 })
                 .flatten()
@@ -855,10 +855,14 @@
     let config = snap.config.runnables();
     match cargo_spec {
         Some(spec) => {
-            let all_targets = !snap.analysis.is_crate_no_std(spec.crate_id)?;
-            for cmd in ["check", "test"] {
+            let is_crate_no_std = snap.analysis.is_crate_no_std(spec.crate_id)?;
+            for cmd in ["check", "run", "test"] {
+                if cmd == "run" && spec.target_kind != TargetKind::Bin {
+                    continue;
+                }
                 let mut cargo_args =
                     vec![cmd.to_owned(), "--package".to_owned(), spec.package.clone()];
+                let all_targets = cmd != "run" && !is_crate_no_std;
                 if all_targets {
                     cargo_args.push("--all-targets".to_owned());
                 }
@@ -930,16 +934,18 @@
 
 pub(crate) fn handle_completion(
     snap: GlobalStateSnapshot,
-    params: lsp_types::CompletionParams,
+    lsp_types::CompletionParams { text_document_position, context,.. }: lsp_types::CompletionParams,
 ) -> anyhow::Result<Option<lsp_types::CompletionResponse>> {
     let _p = tracing::span!(tracing::Level::INFO, "handle_completion").entered();
-    let text_document_position = params.text_document_position.clone();
-    let position = from_proto::file_position(&snap, params.text_document_position)?;
+    let mut position = from_proto::file_position(&snap, text_document_position.clone())?;
+    let line_index = snap.file_line_index(position.file_id)?;
     let completion_trigger_character =
-        params.context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next());
+        context.and_then(|ctx| ctx.trigger_character).and_then(|s| s.chars().next());
 
     let source_root = snap.analysis.source_root(position.file_id)?;
     let completion_config = &snap.config.completion(Some(source_root));
+    // FIXME: We should fix up the position when retrying the cancelled request instead
+    position.offset = position.offset.min(line_index.index.len());
     let items = match snap.analysis.completions(
         completion_config,
         position,
@@ -948,10 +954,14 @@
         None => return Ok(None),
         Some(items) => items,
     };
-    let line_index = snap.file_line_index(position.file_id)?;
 
-    let items =
-        to_proto::completion_items(&snap.config, &line_index, text_document_position, items);
+    let items = to_proto::completion_items(
+        &snap.config,
+        &line_index,
+        snap.file_version(position.file_id),
+        text_document_position,
+        items,
+    );
 
     let completion_list = lsp_types::CompletionList { is_incomplete: true, items };
     Ok(Some(completion_list.into()))
@@ -970,16 +980,16 @@
         .into());
     }
 
-    let data = match original_completion.data.take() {
-        Some(it) => it,
-        None => return Ok(original_completion),
-    };
+    let Some(data) = original_completion.data.take() else { return Ok(original_completion) };
 
     let resolve_data: lsp_ext::CompletionResolveData = serde_json::from_value(data)?;
 
     let file_id = from_proto::file_id(&snap, &resolve_data.position.text_document.uri)?;
     let line_index = snap.file_line_index(file_id)?;
-    let offset = from_proto::offset(&line_index, resolve_data.position.position)?;
+    // FIXME: We should fix up the position when retrying the cancelled request instead
+    let Ok(offset) = from_proto::offset(&line_index, resolve_data.position.position) else {
+        return Ok(original_completion);
+    };
     let source_root = snap.analysis.source_root(file_id)?;
 
     let additional_edits = snap
@@ -1236,8 +1246,11 @@
         frange,
     )?;
     for (index, assist) in assists.into_iter().enumerate() {
-        let resolve_data =
-            if code_action_resolve_cap { Some((index, params.clone())) } else { None };
+        let resolve_data = if code_action_resolve_cap {
+            Some((index, params.clone(), snap.file_version(file_id)))
+        } else {
+            None
+        };
         let code_action = to_proto::code_action(&snap, assist, resolve_data)?;
 
         // Check if the client supports the necessary `ResourceOperation`s.
@@ -1276,12 +1289,14 @@
     mut code_action: lsp_ext::CodeAction,
 ) -> anyhow::Result<lsp_ext::CodeAction> {
     let _p = tracing::span!(tracing::Level::INFO, "handle_code_action_resolve").entered();
-    let params = match code_action.data.take() {
-        Some(it) => it,
-        None => return Err(invalid_params_error("code action without data".to_owned()).into()),
+    let Some(params) = code_action.data.take() else {
+        return Err(invalid_params_error("code action without data".to_owned()).into());
     };
 
     let file_id = from_proto::file_id(&snap, &params.code_action_params.text_document.uri)?;
+    if snap.file_version(file_id) != params.version {
+        return Err(invalid_params_error("stale code action".to_owned()).into());
+    }
     let line_index = snap.file_line_index(file_id)?;
     let range = from_proto::text_range(&line_index, params.code_action_params.range)?;
     let frange = FileRange { file_id, range };
@@ -1407,12 +1422,11 @@
 
 pub(crate) fn handle_code_lens_resolve(
     snap: GlobalStateSnapshot,
-    code_lens: CodeLens,
+    mut code_lens: CodeLens,
 ) -> anyhow::Result<CodeLens> {
-    if code_lens.data.is_none() {
-        return Ok(code_lens);
-    }
-    let Some(annotation) = from_proto::annotation(&snap, code_lens.clone())? else {
+    let Some(data) = code_lens.data.take() else { return Ok(code_lens) };
+    let resolve = serde_json::from_value::<lsp_ext::CodeLensResolveData>(data)?;
+    let Some(annotation) = from_proto::annotation(&snap, code_lens.range, resolve)? else {
         return Ok(code_lens);
     };
     let annotation = snap.analysis.resolve_annotation(annotation)?;
@@ -1491,6 +1505,10 @@
     )?;
     let line_index = snap.file_line_index(file_id)?;
     let source_root = snap.analysis.source_root(file_id)?;
+    let range = TextRange::new(
+        range.start().min(line_index.index.len()),
+        range.end().min(line_index.index.len()),
+    );
 
     let inlay_hints_config = snap.config.inlay_hints(Some(source_root));
     Ok(Some(
@@ -1518,8 +1536,12 @@
 
     let Some(data) = original_hint.data.take() else { return Ok(original_hint) };
     let resolve_data: lsp_ext::InlayHintResolveData = serde_json::from_value(data)?;
-    let Some(hash) = resolve_data.hash.parse().ok() else { return Ok(original_hint) };
     let file_id = FileId::from_raw(resolve_data.file_id);
+    if resolve_data.version != snap.file_version(file_id) {
+        tracing::warn!("Inlay hint resolve data is outdated");
+        return Ok(original_hint);
+    }
+    let Some(hash) = resolve_data.hash.parse().ok() else { return Ok(original_hint) };
     anyhow::ensure!(snap.file_exists(file_id), "Invalid LSP resolve data");
 
     let line_index = snap.file_line_index(file_id)?;
@@ -1758,12 +1780,13 @@
     let _p = tracing::span!(tracing::Level::INFO, "handle_open_docs").entered();
     let position = from_proto::file_position(&snap, params)?;
 
-    let ws_and_sysroot = snap.workspaces.iter().find_map(|ws| match ws {
-        ProjectWorkspace::Cargo { cargo, sysroot, .. } => Some((cargo, sysroot.as_ref().ok())),
-        ProjectWorkspace::Json { .. } => None,
-        ProjectWorkspace::DetachedFile { cargo_script, sysroot, .. } => {
-            cargo_script.as_ref().zip(Some(sysroot.as_ref().ok()))
+    let ws_and_sysroot = snap.workspaces.iter().find_map(|ws| match &ws.kind {
+        ProjectWorkspaceKind::Cargo { cargo, .. }
+        | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. } => {
+            Some((cargo, ws.sysroot.as_ref().ok()))
         }
+        ProjectWorkspaceKind::Json { .. } => None,
+        ProjectWorkspaceKind::DetachedFile { .. } => None,
     });
 
     let (cargo, sysroot) = match ws_and_sysroot {
@@ -1836,7 +1859,7 @@
     snap: GlobalStateSnapshot,
     params: lsp_types::TextDocumentPositionParams,
 ) -> anyhow::Result<Option<lsp_ext::RecursiveMemoryLayout>> {
-    let _p = tracing::span!(tracing::Level::INFO, "view_recursive_memory_layout").entered();
+    let _p = tracing::span!(tracing::Level::INFO, "handle_view_recursive_memory_layout").entered();
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
     let line_index = snap.file_line_index(file_id)?;
     let offset = from_proto::offset(&line_index, params.position)?;
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
index 7b385ca..cc83d62 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -153,6 +153,7 @@
             prefer_no_std: false,
             prefer_prelude: true,
             limit: None,
+            term_search_fuel: 200,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -197,6 +198,7 @@
             prefer_no_std: false,
             prefer_prelude: true,
             limit: None,
+            term_search_fuel: 200,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -239,6 +241,7 @@
             prefer_no_std: false,
             prefer_prelude: true,
             limit: None,
+            term_search_fuel: 200,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -295,6 +298,7 @@
         },
         prefer_no_std: false,
         prefer_prelude: false,
+        term_search_fuel: 400,
     };
     host.analysis()
         .diagnostics(&diagnostics_config, ide::AssistResolveStrategy::None, file_id)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
index 12f8e71..2cf9b53 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
@@ -2,6 +2,7 @@
 
 #![allow(clippy::disallowed_types)]
 
+use std::ops;
 use std::path::PathBuf;
 
 use ide_db::line_index::WideEncoding;
@@ -494,10 +495,12 @@
 }
 
 #[derive(Deserialize, Serialize, PartialEq, Eq, Clone)]
+#[serde(rename_all = "camelCase")]
 pub struct ServerStatusParams {
     pub health: Health,
     pub quiescent: bool,
     pub message: Option<String>,
+    pub workspace_info: Option<String>,
 }
 
 #[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
@@ -508,6 +511,16 @@
     Error,
 }
 
+impl ops::BitOrAssign for Health {
+    fn bitor_assign(&mut self, rhs: Self) {
+        *self = match (*self, rhs) {
+            (Health::Error, _) | (_, Health::Error) => Health::Error,
+            (Health::Warning, _) | (_, Health::Warning) => Health::Warning,
+            _ => Health::Ok,
+        }
+    }
+}
+
 pub enum CodeActionRequest {}
 
 impl Request for CodeActionRequest {
@@ -548,6 +561,7 @@
 pub struct CodeActionData {
     pub code_action_params: lsp_types::CodeActionParams,
     pub id: String,
+    pub version: Option<i32>,
 }
 
 #[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)]
@@ -789,6 +803,7 @@
 pub struct CompletionResolveData {
     pub position: lsp_types::TextDocumentPositionParams,
     pub imports: Vec<CompletionImport>,
+    pub version: Option<i32>,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
@@ -796,6 +811,7 @@
     pub file_id: u32,
     // This is a string instead of a u64 as javascript can't represent u64 fully
     pub hash: String,
+    pub version: Option<i32>,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
index f42985a..b6b2029 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
@@ -9,10 +9,8 @@
 use vfs::AbsPathBuf;
 
 use crate::{
-    from_json,
     global_state::GlobalStateSnapshot,
     line_index::{LineIndex, PositionEncoding},
-    lsp::utils::invalid_params_error,
     lsp_ext,
 };
 
@@ -105,16 +103,13 @@
 
 pub(crate) fn annotation(
     snap: &GlobalStateSnapshot,
-    code_lens: lsp_types::CodeLens,
+    range: lsp_types::Range,
+    data: lsp_ext::CodeLensResolveData,
 ) -> anyhow::Result<Option<Annotation>> {
-    let data =
-        code_lens.data.ok_or_else(|| invalid_params_error("code lens without data".to_owned()))?;
-    let resolve = from_json::<lsp_ext::CodeLensResolveData>("CodeLensResolveData", &data)?;
-
-    match resolve.kind {
+    match data.kind {
         lsp_ext::CodeLensResolveDataKind::Impls(params) => {
             if snap.url_file_version(&params.text_document_position_params.text_document.uri)
-                != Some(resolve.version)
+                != Some(data.version)
             {
                 return Ok(None);
             }
@@ -123,19 +118,19 @@
             let line_index = snap.file_line_index(file_id)?;
 
             Ok(Annotation {
-                range: text_range(&line_index, code_lens.range)?,
+                range: text_range(&line_index, range)?,
                 kind: AnnotationKind::HasImpls { pos, data: None },
             })
         }
         lsp_ext::CodeLensResolveDataKind::References(params) => {
-            if snap.url_file_version(&params.text_document.uri) != Some(resolve.version) {
+            if snap.url_file_version(&params.text_document.uri) != Some(data.version) {
                 return Ok(None);
             }
             let pos @ FilePosition { file_id, .. } = file_position(snap, params)?;
             let line_index = snap.file_line_index(file_id)?;
 
             Ok(Annotation {
-                range: text_range(&line_index, code_lens.range)?,
+                range: text_range(&line_index, range)?,
                 kind: AnnotationKind::HasReferences { pos, data: None },
             })
         }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index d02f461..03daccc 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -225,13 +225,14 @@
 pub(crate) fn completion_items(
     config: &Config,
     line_index: &LineIndex,
+    version: Option<i32>,
     tdpp: lsp_types::TextDocumentPositionParams,
     items: Vec<CompletionItem>,
 ) -> Vec<lsp_types::CompletionItem> {
     let max_relevance = items.iter().map(|it| it.relevance.score()).max().unwrap_or_default();
     let mut res = Vec::with_capacity(items.len());
     for item in items {
-        completion_item(&mut res, config, line_index, &tdpp, max_relevance, item);
+        completion_item(&mut res, config, line_index, version, &tdpp, max_relevance, item);
     }
 
     if let Some(limit) = config.completion(None).limit {
@@ -246,6 +247,7 @@
     acc: &mut Vec<lsp_types::CompletionItem>,
     config: &Config,
     line_index: &LineIndex,
+    version: Option<i32>,
     tdpp: &lsp_types::TextDocumentPositionParams,
     max_relevance: u32,
     item: CompletionItem,
@@ -328,7 +330,7 @@
             })
             .collect::<Vec<_>>();
         if !imports.is_empty() {
-            let data = lsp_ext::CompletionResolveData { position: tdpp.clone(), imports };
+            let data = lsp_ext::CompletionResolveData { position: tdpp.clone(), imports, version };
             lsp_item.data = Some(to_value(data).unwrap());
         }
     }
@@ -483,6 +485,7 @@
             to_value(lsp_ext::InlayHintResolveData {
                 file_id: file_id.index(),
                 hash: hash.to_string(),
+                version: snap.file_version(file_id),
             })
             .unwrap(),
         ),
@@ -1318,7 +1321,7 @@
 pub(crate) fn code_action(
     snap: &GlobalStateSnapshot,
     assist: Assist,
-    resolve_data: Option<(usize, lsp_types::CodeActionParams)>,
+    resolve_data: Option<(usize, lsp_types::CodeActionParams, Option<i32>)>,
 ) -> Cancellable<lsp_ext::CodeAction> {
     let mut res = lsp_ext::CodeAction {
         title: assist.label.to_string(),
@@ -1336,10 +1339,11 @@
 
     match (assist.source_change, resolve_data) {
         (Some(it), _) => res.edit = Some(snippet_workspace_edit(snap, it)?),
-        (None, Some((index, code_action_params))) => {
+        (None, Some((index, code_action_params, version))) => {
             res.data = Some(lsp_ext::CodeActionData {
                 id: format!("{}:{}:{index}", assist.id.0, assist.id.1.name()),
                 code_action_params,
+                version,
             });
         }
         (None, None) => {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index f37b25f..5435be3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -12,6 +12,7 @@
 use lsp_server::{Connection, Notification, Request};
 use lsp_types::{notification::Notification as _, TextDocumentIdentifier};
 use stdx::thread::ThreadIntent;
+use tracing::{span, Level};
 use vfs::FileId;
 
 use crate::{
@@ -44,7 +45,7 @@
     // https://github.com/rust-lang/rust-analyzer/issues/2835
     #[cfg(windows)]
     unsafe {
-        use winapi::um::processthreadsapi::*;
+        use windows_sys::Win32::System::Threading::*;
         let thread = GetCurrentThread();
         let thread_priority_above_normal = 1;
         SetThreadPriority(thread, thread_priority_above_normal);
@@ -229,8 +230,7 @@
     fn handle_event(&mut self, event: Event) -> anyhow::Result<()> {
         let loop_start = Instant::now();
         // NOTE: don't count blocking select! call as a loop-turn time
-        let _p = tracing::span!(tracing::Level::INFO, "GlobalState::handle_event", event = %event)
-            .entered();
+        let _p = tracing::span!(Level::INFO, "GlobalState::handle_event", event = %event).entered();
 
         let event_dbg_msg = format!("{event:?}");
         tracing::debug!(?loop_start, ?event, "handle_event");
@@ -669,9 +669,12 @@
     }
 
     fn handle_vfs_msg(&mut self, message: vfs::loader::Message) {
+        let _p = tracing::span!(Level::INFO, "GlobalState::handle_vfs_msg").entered();
         let is_changed = matches!(message, vfs::loader::Message::Changed { .. });
         match message {
             vfs::loader::Message::Changed { files } | vfs::loader::Message::Loaded { files } => {
+                let _p = tracing::span!(Level::INFO, "GlobalState::handle_vfs_msg{changed/load}")
+                    .entered();
                 let vfs = &mut self.vfs.write().0;
                 for (path, contents) in files {
                     let path = VfsPath::from(path);
@@ -685,6 +688,8 @@
                 }
             }
             vfs::loader::Message::Progress { n_total, n_done, dir, config_version } => {
+                let _p =
+                    tracing::span!(Level::INFO, "GlobalState::handle_vfs_mgs/progress").entered();
                 always!(config_version <= self.vfs_config_version);
 
                 let state = match n_done {
@@ -867,6 +872,8 @@
 
     /// Registers and handles a request. This should only be called once per incoming request.
     fn on_new_request(&mut self, request_received: Instant, req: Request) {
+        let _p =
+            span!(Level::INFO, "GlobalState::on_new_request", req.method = ?req.method).entered();
         self.register_request(&req, request_received);
         self.on_request(req);
     }
@@ -894,6 +901,10 @@
         use crate::handlers::request as handlers;
         use lsp_types::request as lsp_request;
 
+        const RETRY: bool = true;
+        const NO_RETRY: bool = false;
+
+        #[rustfmt::skip]
         dispatcher
             // Request handlers that must run on the main thread
             // because they mutate GlobalState:
@@ -919,67 +930,65 @@
             // analysis on the main thread because that would block other
             // requests. Instead, we run these request handlers on higher priority
             // threads in the threadpool.
-            .on_latency_sensitive::<lsp_request::Completion>(handlers::handle_completion)
-            .on_latency_sensitive::<lsp_request::ResolveCompletionItem>(
-                handlers::handle_completion_resolve,
-            )
-            .on_latency_sensitive::<lsp_request::SemanticTokensFullRequest>(
-                handlers::handle_semantic_tokens_full,
-            )
-            .on_latency_sensitive::<lsp_request::SemanticTokensFullDeltaRequest>(
-                handlers::handle_semantic_tokens_full_delta,
-            )
-            .on_latency_sensitive::<lsp_request::SemanticTokensRangeRequest>(
-                handlers::handle_semantic_tokens_range,
-            )
+            // FIXME: Retrying can make the result of this stale?
+            .on_latency_sensitive::<RETRY, lsp_request::Completion>(handlers::handle_completion)
+            // FIXME: Retrying can make the result of this stale
+            .on_latency_sensitive::<RETRY, lsp_request::ResolveCompletionItem>(handlers::handle_completion_resolve)
+            .on_latency_sensitive::<RETRY, lsp_request::SemanticTokensFullRequest>(handlers::handle_semantic_tokens_full)
+            .on_latency_sensitive::<RETRY, lsp_request::SemanticTokensFullDeltaRequest>(handlers::handle_semantic_tokens_full_delta)
+            .on_latency_sensitive::<NO_RETRY, lsp_request::SemanticTokensRangeRequest>(handlers::handle_semantic_tokens_range)
+            // FIXME: Some of these NO_RETRY could be retries if the file they are interested didn't change.
             // All other request handlers
-            .on::<lsp_ext::FetchDependencyList>(handlers::fetch_dependency_list)
-            .on::<lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
-            .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
-            .on::<lsp_ext::ViewHir>(handlers::handle_view_hir)
-            .on::<lsp_ext::ViewMir>(handlers::handle_view_mir)
-            .on::<lsp_ext::InterpretFunction>(handlers::handle_interpret_function)
-            .on::<lsp_ext::ViewFileText>(handlers::handle_view_file_text)
-            .on::<lsp_ext::ViewCrateGraph>(handlers::handle_view_crate_graph)
-            .on::<lsp_ext::ViewItemTree>(handlers::handle_view_item_tree)
-            .on::<lsp_ext::DiscoverTest>(handlers::handle_discover_test)
-            .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
-            .on::<lsp_ext::ParentModule>(handlers::handle_parent_module)
-            .on::<lsp_ext::Runnables>(handlers::handle_runnables)
-            .on::<lsp_ext::RelatedTests>(handlers::handle_related_tests)
-            .on::<lsp_ext::CodeActionRequest>(handlers::handle_code_action)
-            .on::<lsp_ext::CodeActionResolveRequest>(handlers::handle_code_action_resolve)
-            .on::<lsp_ext::HoverRequest>(handlers::handle_hover)
-            .on::<lsp_ext::ExternalDocs>(handlers::handle_open_docs)
-            .on::<lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
-            .on::<lsp_ext::MoveItem>(handlers::handle_move_item)
-            .on::<lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol)
-            .on::<lsp_request::DocumentSymbolRequest>(handlers::handle_document_symbol)
-            .on::<lsp_request::GotoDefinition>(handlers::handle_goto_definition)
-            .on::<lsp_request::GotoDeclaration>(handlers::handle_goto_declaration)
-            .on::<lsp_request::GotoImplementation>(handlers::handle_goto_implementation)
-            .on::<lsp_request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
-            .on_no_retry::<lsp_request::InlayHintRequest>(handlers::handle_inlay_hints)
-            .on::<lsp_request::InlayHintResolveRequest>(handlers::handle_inlay_hints_resolve)
-            .on::<lsp_request::CodeLensRequest>(handlers::handle_code_lens)
-            .on::<lsp_request::CodeLensResolve>(handlers::handle_code_lens_resolve)
-            .on::<lsp_request::FoldingRangeRequest>(handlers::handle_folding_range)
-            .on::<lsp_request::SignatureHelpRequest>(handlers::handle_signature_help)
-            .on::<lsp_request::PrepareRenameRequest>(handlers::handle_prepare_rename)
-            .on::<lsp_request::Rename>(handlers::handle_rename)
-            .on::<lsp_request::References>(handlers::handle_references)
-            .on::<lsp_request::DocumentHighlightRequest>(handlers::handle_document_highlight)
-            .on::<lsp_request::CallHierarchyPrepare>(handlers::handle_call_hierarchy_prepare)
-            .on::<lsp_request::CallHierarchyIncomingCalls>(handlers::handle_call_hierarchy_incoming)
-            .on::<lsp_request::CallHierarchyOutgoingCalls>(handlers::handle_call_hierarchy_outgoing)
-            .on::<lsp_request::WillRenameFiles>(handlers::handle_will_rename_files)
-            .on::<lsp_ext::Ssr>(handlers::handle_ssr)
-            .on::<lsp_ext::ViewRecursiveMemoryLayout>(handlers::handle_view_recursive_memory_layout)
+            .on::<RETRY, lsp_request::DocumentSymbolRequest>(handlers::handle_document_symbol)
+            .on::<RETRY, lsp_request::FoldingRangeRequest>(handlers::handle_folding_range)
+            .on::<NO_RETRY, lsp_request::SignatureHelpRequest>(handlers::handle_signature_help)
+            .on::<RETRY, lsp_request::WillRenameFiles>(handlers::handle_will_rename_files)
+            .on::<NO_RETRY, lsp_request::GotoDefinition>(handlers::handle_goto_definition)
+            .on::<NO_RETRY, lsp_request::GotoDeclaration>(handlers::handle_goto_declaration)
+            .on::<NO_RETRY, lsp_request::GotoImplementation>(handlers::handle_goto_implementation)
+            .on::<NO_RETRY, lsp_request::GotoTypeDefinition>(handlers::handle_goto_type_definition)
+            .on::<RETRY, lsp_request::InlayHintRequest>(handlers::handle_inlay_hints)
+            .on::<RETRY, lsp_request::InlayHintResolveRequest>(handlers::handle_inlay_hints_resolve)
+            .on::<NO_RETRY, lsp_request::CodeLensRequest>(handlers::handle_code_lens)
+            .on::<RETRY, lsp_request::CodeLensResolve>(handlers::handle_code_lens_resolve)
+            .on::<NO_RETRY, lsp_request::PrepareRenameRequest>(handlers::handle_prepare_rename)
+            .on::<NO_RETRY, lsp_request::Rename>(handlers::handle_rename)
+            .on::<NO_RETRY, lsp_request::References>(handlers::handle_references)
+            .on::<NO_RETRY, lsp_request::DocumentHighlightRequest>(handlers::handle_document_highlight)
+            .on::<NO_RETRY, lsp_request::CallHierarchyPrepare>(handlers::handle_call_hierarchy_prepare)
+            .on::<NO_RETRY, lsp_request::CallHierarchyIncomingCalls>(handlers::handle_call_hierarchy_incoming)
+            .on::<NO_RETRY, lsp_request::CallHierarchyOutgoingCalls>(handlers::handle_call_hierarchy_outgoing)
+            // All other request handlers (lsp extension)
+            .on::<RETRY, lsp_ext::FetchDependencyList>(handlers::fetch_dependency_list)
+            .on::<RETRY, lsp_ext::AnalyzerStatus>(handlers::handle_analyzer_status)
+            .on::<RETRY, lsp_ext::ViewFileText>(handlers::handle_view_file_text)
+            .on::<RETRY, lsp_ext::ViewCrateGraph>(handlers::handle_view_crate_graph)
+            .on::<RETRY, lsp_ext::ViewItemTree>(handlers::handle_view_item_tree)
+            .on::<RETRY, lsp_ext::DiscoverTest>(handlers::handle_discover_test)
+            .on::<RETRY, lsp_ext::WorkspaceSymbol>(handlers::handle_workspace_symbol)
+            .on::<NO_RETRY, lsp_ext::Ssr>(handlers::handle_ssr)
+            .on::<NO_RETRY, lsp_ext::ViewRecursiveMemoryLayout>(handlers::handle_view_recursive_memory_layout)
+            .on::<NO_RETRY, lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
+            .on::<NO_RETRY, lsp_ext::ViewHir>(handlers::handle_view_hir)
+            .on::<NO_RETRY, lsp_ext::ViewMir>(handlers::handle_view_mir)
+            .on::<NO_RETRY, lsp_ext::InterpretFunction>(handlers::handle_interpret_function)
+            .on::<NO_RETRY, lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
+            .on::<NO_RETRY, lsp_ext::ParentModule>(handlers::handle_parent_module)
+            .on::<NO_RETRY, lsp_ext::Runnables>(handlers::handle_runnables)
+            .on::<NO_RETRY, lsp_ext::RelatedTests>(handlers::handle_related_tests)
+            .on::<NO_RETRY, lsp_ext::CodeActionRequest>(handlers::handle_code_action)
+            .on::<RETRY, lsp_ext::CodeActionResolveRequest>(handlers::handle_code_action_resolve)
+            .on::<NO_RETRY, lsp_ext::HoverRequest>(handlers::handle_hover)
+            .on::<NO_RETRY, lsp_ext::ExternalDocs>(handlers::handle_open_docs)
+            .on::<NO_RETRY, lsp_ext::OpenCargoToml>(handlers::handle_open_cargo_toml)
+            .on::<NO_RETRY, lsp_ext::MoveItem>(handlers::handle_move_item)
             .finish();
     }
 
     /// Handles an incoming notification.
     fn on_notification(&mut self, not: Notification) -> anyhow::Result<()> {
+        let _p =
+            span!(Level::INFO, "GlobalState::on_notification", not.method = ?not.method).entered();
         use crate::handlers::notification as handlers;
         use lsp_types::notification as notifs;
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 5d8a66c..fd14efa 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -25,7 +25,7 @@
 use itertools::Itertools;
 use load_cargo::{load_proc_macro, ProjectFolders};
 use proc_macro_api::ProcMacroServer;
-use project_model::{ProjectWorkspace, WorkspaceBuildScripts};
+use project_model::{ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, WorkspaceBuildScripts};
 use stdx::{format_to, thread::ThreadIntent};
 use triomphe::Arc;
 use vfs::{AbsPath, AbsPathBuf, ChangeKind};
@@ -103,81 +103,48 @@
             health: lsp_ext::Health::Ok,
             quiescent: self.is_quiescent(),
             message: None,
+            workspace_info: None,
         };
         let mut message = String::new();
 
+        if !self.config.cargo_autoreload()
+            && self.is_quiescent()
+            && self.fetch_workspaces_queue.op_requested()
+        {
+            status.health |= lsp_ext::Health::Warning;
+            message.push_str("Auto-reloading is disabled and the workspace has changed, a manual workspace reload is required.\n\n");
+        }
+
         if self.build_deps_changed {
-            status.health = lsp_ext::Health::Warning;
+            status.health |= lsp_ext::Health::Warning;
             message.push_str(
                 "Proc-macros and/or build scripts have changed and need to be rebuilt.\n\n",
             );
         }
         if self.fetch_build_data_error().is_err() {
-            status.health = lsp_ext::Health::Warning;
+            status.health |= lsp_ext::Health::Warning;
             message.push_str("Failed to run build scripts of some packages.\n\n");
         }
-        if self.proc_macro_clients.iter().any(|it| it.is_err()) {
-            status.health = lsp_ext::Health::Warning;
-            message.push_str("Failed to spawn one or more proc-macro servers.\n\n");
-            for err in self.proc_macro_clients.iter() {
-                if let Err(err) = err {
-                    format_to!(message, "- {err}\n");
-                }
-            }
-        }
-        if !self.config.cargo_autoreload()
-            && self.is_quiescent()
-            && self.fetch_workspaces_queue.op_requested()
-        {
-            status.health = lsp_ext::Health::Warning;
-            message.push_str("Auto-reloading is disabled and the workspace has changed, a manual workspace reload is required.\n\n");
-        }
-        if self.config.linked_or_discovered_projects().is_empty()
-            && self.config.detached_files().is_empty()
-            && self.config.notifications().cargo_toml_not_found
-        {
-            status.health = lsp_ext::Health::Warning;
-            message.push_str("Failed to discover workspace.\n");
-            message.push_str("Consider adding the `Cargo.toml` of the workspace to the [`linkedProjects`](https://rust-analyzer.github.io/manual.html#rust-analyzer.linkedProjects) setting.\n\n");
-        }
+
         if let Some(err) = &self.config_errors {
-            status.health = lsp_ext::Health::Warning;
+            status.health |= lsp_ext::Health::Warning;
             format_to!(message, "{err}\n");
         }
         if let Some(err) = &self.last_flycheck_error {
-            status.health = lsp_ext::Health::Warning;
+            status.health |= lsp_ext::Health::Warning;
             message.push_str(err);
             message.push('\n');
         }
 
-        for ws in self.workspaces.iter() {
-            let (ProjectWorkspace::Cargo { sysroot, .. }
-            | ProjectWorkspace::Json { sysroot, .. }
-            | ProjectWorkspace::DetachedFile { sysroot, .. }) = ws;
-            match sysroot {
-                Err(None) => (),
-                Err(Some(e)) => {
-                    status.health = lsp_ext::Health::Warning;
-                    message.push_str(e);
-                    message.push_str("\n\n");
-                }
-                Ok(s) => {
-                    if let Some(e) = s.loading_warning() {
-                        status.health = lsp_ext::Health::Warning;
-                        message.push_str(&e);
-                        message.push_str("\n\n");
-                    }
-                }
-            }
-            if let ProjectWorkspace::Cargo { rustc: Err(Some(e)), .. } = ws {
-                status.health = lsp_ext::Health::Warning;
-                message.push_str(e);
-                message.push_str("\n\n");
-            }
+        if self.config.linked_or_discovered_projects().is_empty()
+            && self.config.detached_files().is_empty()
+        {
+            status.health |= lsp_ext::Health::Warning;
+            message.push_str("Failed to discover workspace.\n");
+            message.push_str("Consider adding the `Cargo.toml` of the workspace to the [`linkedProjects`](https://rust-analyzer.github.io/manual.html#rust-analyzer.linkedProjects) setting.\n\n");
         }
-
         if self.fetch_workspace_error().is_err() {
-            status.health = lsp_ext::Health::Error;
+            status.health |= lsp_ext::Health::Error;
             message.push_str("Failed to load workspaces.");
 
             if self.config.has_linked_projects() {
@@ -193,9 +160,63 @@
             message.push_str("\n\n");
         }
 
+        if !self.workspaces.is_empty() {
+            let proc_macro_clients =
+                self.proc_macro_clients.iter().map(Some).chain(iter::repeat_with(|| None));
+
+            let mut workspace_info = "Loaded workspaces:\n".to_owned();
+            for (ws, proc_macro_client) in self.workspaces.iter().zip(proc_macro_clients) {
+                format_to!(workspace_info, "- `{}`\n", ws.manifest_or_root());
+                format_to!(workspace_info, "    - sysroot:");
+
+                match ws.sysroot.as_ref() {
+                    Err(None) => format_to!(workspace_info, " None"),
+                    Err(Some(e)) => {
+                        status.health |= lsp_ext::Health::Warning;
+                        format_to!(workspace_info, " {e}");
+                    }
+                    Ok(s) => {
+                        format_to!(workspace_info, " `{}`", s.root().to_string());
+                        if let Some(err) = s
+                            .check_has_core()
+                            .err()
+                            .inspect(|_| status.health |= lsp_ext::Health::Warning)
+                        {
+                            format_to!(workspace_info, " ({err})");
+                        }
+                        if let Some(src_root) = s.src_root() {
+                            format_to!(
+                                workspace_info,
+                                "\n        - sysroot source: `{}`",
+                                src_root
+                            );
+                        }
+                        format_to!(workspace_info, "\n");
+                    }
+                }
+
+                if let ProjectWorkspaceKind::Cargo { rustc: Err(Some(e)), .. } = &ws.kind {
+                    status.health |= lsp_ext::Health::Warning;
+                    format_to!(workspace_info, "    - rustc workspace: {e}\n");
+                };
+                if let Some(proc_macro_client) = proc_macro_client {
+                    format_to!(workspace_info, "    - proc-macro server: ");
+                    match proc_macro_client {
+                        Ok(it) => format_to!(workspace_info, "`{}`\n", it.path()),
+                        Err(e) => {
+                            status.health |= lsp_ext::Health::Warning;
+                            format_to!(workspace_info, "{e}\n")
+                        }
+                    }
+                }
+            }
+            status.workspace_info = Some(workspace_info);
+        }
+
         if !message.is_empty() {
             status.message = Some(message.trim_end().to_owned());
         }
+
         status
     }
 
@@ -204,7 +225,14 @@
 
         self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, {
             let linked_projects = self.config.linked_or_discovered_projects();
-            let detached_files = self.config.detached_files().to_vec();
+            let detached_files: Vec<_> = self
+                .config
+                .detached_files()
+                .iter()
+                .cloned()
+                .map(ManifestPath::try_from)
+                .filter_map(Result::ok)
+                .collect();
             let cargo_config = self.config.cargo();
 
             move |sender| {
@@ -494,23 +522,28 @@
                     None => ws.find_sysroot_proc_macro_srv()?,
                 };
 
-                let env =
-                    match ws {
-                        ProjectWorkspace::Cargo { cargo_config_extra_env, sysroot, .. } => {
-                            cargo_config_extra_env
-                                .iter()
-                                .chain(self.config.extra_env())
-                                .map(|(a, b)| (a.clone(), b.clone()))
-                                .chain(sysroot.as_ref().map(|it| {
-                                    ("RUSTUP_TOOLCHAIN".to_owned(), it.root().to_string())
-                                }))
-                                .collect()
-                        }
-                        _ => Default::default(),
-                    };
+                let env = match &ws.kind {
+                    ProjectWorkspaceKind::Cargo { cargo_config_extra_env, .. }
+                    | ProjectWorkspaceKind::DetachedFile {
+                        cargo: Some(_),
+                        cargo_config_extra_env,
+                        ..
+                    } => cargo_config_extra_env
+                        .iter()
+                        .chain(self.config.extra_env())
+                        .map(|(a, b)| (a.clone(), b.clone()))
+                        .chain(
+                            ws.sysroot
+                                .as_ref()
+                                .map(|it| ("RUSTUP_TOOLCHAIN".to_owned(), it.root().to_string())),
+                        )
+                        .collect(),
+
+                    _ => Default::default(),
+                };
                 tracing::info!("Using proc-macro server at {path}");
 
-                ProcMacroServer::spawn(path.clone(), &env).map_err(|err| {
+                ProcMacroServer::spawn(&path, &env).map_err(|err| {
                     tracing::error!(
                         "Failed to run proc-macro server from path {path}, error: {err:?}",
                     );
@@ -554,8 +587,8 @@
         self.detached_files = self
             .workspaces
             .iter()
-            .filter_map(|ws| match ws {
-                ProjectWorkspace::DetachedFile { file, .. } => Some(file.clone()),
+            .filter_map(|ws| match &ws.kind {
+                ProjectWorkspaceKind::DetachedFile { file, .. } => Some(file.clone()),
                 _ => None,
             })
             .collect();
@@ -659,33 +692,37 @@
                 config,
                 None,
                 self.config.root_path().clone(),
+                None,
             )],
             flycheck::InvocationStrategy::PerWorkspace => {
                 self.workspaces
                     .iter()
                     .enumerate()
-                    .filter_map(|(id, w)| match w {
-                        ProjectWorkspace::Cargo { cargo, sysroot, .. } => Some((
+                    .filter_map(|(id, ws)| {
+                        Some((
                             id,
-                            cargo.workspace_root(),
-                            sysroot.as_ref().ok().map(|sysroot| sysroot.root().to_owned()),
-                        )),
-                        ProjectWorkspace::Json { project, sysroot, .. } => {
-                            // Enable flychecks for json projects if a custom flycheck command was supplied
-                            // in the workspace configuration.
-                            match config {
-                                FlycheckConfig::CustomCommand { .. } => Some((
-                                    id,
-                                    project.path(),
-                                    sysroot.as_ref().ok().map(|sysroot| sysroot.root().to_owned()),
-                                )),
-                                _ => None,
-                            }
-                        }
-                        // FIXME
-                        ProjectWorkspace::DetachedFile { .. } => None,
+                            match &ws.kind {
+                                ProjectWorkspaceKind::Cargo { cargo, .. }
+                                | ProjectWorkspaceKind::DetachedFile {
+                                    cargo: Some((cargo, _)),
+                                    ..
+                                } => (cargo.workspace_root(), Some(cargo.manifest_path())),
+                                ProjectWorkspaceKind::Json(project) => {
+                                    // Enable flychecks for json projects if a custom flycheck command was supplied
+                                    // in the workspace configuration.
+                                    match config {
+                                        FlycheckConfig::CustomCommand { .. } => {
+                                            (project.path(), None)
+                                        }
+                                        _ => return None,
+                                    }
+                                }
+                                ProjectWorkspaceKind::DetachedFile { .. } => return None,
+                            },
+                            ws.sysroot.as_ref().ok().map(|sysroot| sysroot.root().to_owned()),
+                        ))
                     })
-                    .map(|(id, root, sysroot_root)| {
+                    .map(|(id, (root, manifest_path), sysroot_root)| {
                         let sender = sender.clone();
                         FlycheckHandle::spawn(
                             id,
@@ -693,6 +730,7 @@
                             config.clone(),
                             sysroot_root,
                             root.to_path_buf(),
+                            manifest_path.map(|it| it.to_path_buf()),
                         )
                     })
                     .collect()
@@ -722,9 +760,7 @@
         let (other, mut crate_proc_macros) = ws.to_crate_graph(&mut load, extra_env);
         let num_layouts = layouts.len();
         let num_toolchains = toolchains.len();
-        let (ProjectWorkspace::Cargo { toolchain, target_layout, .. }
-        | ProjectWorkspace::Json { toolchain, target_layout, .. }
-        | ProjectWorkspace::DetachedFile { toolchain, target_layout, .. }) = ws;
+        let ProjectWorkspace { toolchain, target_layout, .. } = ws;
 
         let mapping = crate_graph.extend(
             other,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
index f7de5fb..2bcd850 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
@@ -45,7 +45,7 @@
 
 /// `TaskQueue`, like its name suggests, queues tasks.
 ///
-/// This should only be used used if a task must run after [`GlobalState::process_changes`]
+/// This should only be used if a task must run after [`GlobalState::process_changes`]
 /// has been called.
 pub(crate) struct TaskQueue {
     pub(crate) sender: crossbeam_channel::Sender<QueuedTask>,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs
index cf38032..59b229c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/crate_graph.rs
@@ -1,24 +1,31 @@
 use std::path::PathBuf;
 
-use project_model::{CargoWorkspace, ProjectWorkspace, Sysroot, WorkspaceBuildScripts};
+use project_model::{
+    CargoWorkspace, ManifestPath, Metadata, ProjectWorkspace, ProjectWorkspaceKind, Sysroot,
+    WorkspaceBuildScripts,
+};
 use rust_analyzer::ws_to_crate_graph;
 use rustc_hash::FxHashMap;
 use serde::de::DeserializeOwned;
 use vfs::{AbsPathBuf, FileId};
 
 fn load_cargo_with_fake_sysroot(file: &str) -> ProjectWorkspace {
-    let meta = get_test_json_file(file);
-    let cargo_workspace = CargoWorkspace::new(meta);
-    ProjectWorkspace::Cargo {
-        cargo: cargo_workspace,
-        build_scripts: WorkspaceBuildScripts::default(),
+    let meta: Metadata = get_test_json_file(file);
+    let manifest_path =
+        ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap();
+    let cargo_workspace = CargoWorkspace::new(meta, manifest_path);
+    ProjectWorkspace {
+        kind: ProjectWorkspaceKind::Cargo {
+            cargo: cargo_workspace,
+            build_scripts: WorkspaceBuildScripts::default(),
+            rustc: Err(None),
+            cargo_config_extra_env: Default::default(),
+        },
         sysroot: Ok(get_fake_sysroot()),
-        rustc: Err(None),
         rustc_cfg: Vec::new(),
         cfg_overrides: Default::default(),
         toolchain: None,
         target_layout: Err("target_data_layout not loaded".into()),
-        cargo_config_extra_env: Default::default(),
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
index b87f029..5a1397b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -150,6 +150,7 @@
     )
     .with_config(serde_json::json!({
         "cargo": { "sysroot": null },
+        "linkedProjects": ["src/lib.rs"],
     }))
     .server()
     .wait_until_workspace_is_loaded();
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
index f04962a..cf27cc7 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -185,11 +185,7 @@
             roots,
             None,
         );
-        // TODO: don't hardcode src/lib.rs as detached file
-        let mut c = self.config;
-        let p = tmp_dir_path.join("src/lib.rs").to_string();
-        c["detachedFiles"] = serde_json::json!([p]);
-        config.update(c).expect("invalid config");
+        config.update(self.config).expect("invalid config");
         config.rediscover_workspaces();
 
         Server::new(tmp_dir.keep(), config)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
index 3443939..4a7415b 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
@@ -144,6 +144,7 @@
 MIT OR Apache-2.0 OR Zlib
 MIT OR Zlib OR Apache-2.0
 MIT/Apache-2.0
+MPL-2.0
 Unlicense OR MIT
 Unlicense/MIT
 Zlib OR Apache-2.0 OR MIT
diff --git a/src/tools/rust-analyzer/crates/salsa/src/lib.rs b/src/tools/rust-analyzer/crates/salsa/src/lib.rs
index f86683e..5dde0d5 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/lib.rs
@@ -443,7 +443,7 @@
 /// Trait implements by all of the "special types" associated with
 /// each of your queries.
 pub trait Query: Debug + Default + Sized + for<'d> QueryDb<'d> {
-    /// Type that you you give as a parameter -- for queries with zero
+    /// Type that you give as a parameter -- for queries with zero
     /// or more than one input, this will be a tuple.
     type Key: Clone + Debug + Hash + Eq;
 
diff --git a/src/tools/rust-analyzer/crates/salsa/src/lru.rs b/src/tools/rust-analyzer/crates/salsa/src/lru.rs
index edad551..f63f4c1 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/lru.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/lru.rs
@@ -285,7 +285,7 @@
 
 impl Default for LruIndex {
     fn default() -> Self {
-        Self { index: AtomicUsize::new(std::usize::MAX) }
+        Self { index: AtomicUsize::new(usize::MAX) }
     }
 }
 
@@ -299,11 +299,11 @@
     }
 
     fn clear(&self) {
-        self.store(std::usize::MAX);
+        self.store(usize::MAX);
     }
 
     fn is_in_lru(&self) -> bool {
-        self.load() != std::usize::MAX
+        self.load() != usize::MAX
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/salsa/src/revision.rs b/src/tools/rust-analyzer/crates/salsa/src/revision.rs
index 204c088..7f4c333 100644
--- a/src/tools/rust-analyzer/crates/salsa/src/revision.rs
+++ b/src/tools/rust-analyzer/crates/salsa/src/revision.rs
@@ -60,7 +60,7 @@
     /// Increment by 1, returning previous value.
     pub(crate) fn fetch_then_increment(&self) -> Revision {
         let v = self.data.fetch_add(1, Ordering::SeqCst);
-        assert!(v != u32::max_value(), "revision overflow");
+        assert!(v != u32::MAX, "revision overflow");
         Revision::from(v)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
index 6cca116..99824df 100644
--- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
@@ -22,7 +22,7 @@
 
 [target.'cfg(windows)'.dependencies]
 miow = "0.6.0"
-winapi = { version = "0.3.9", features = ["winerror"] }
+windows-sys = { version = "0.52", features = ["Win32_Foundation"] }
 
 [features]
 # Uncomment to enable for the whole crate graph
diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
index 0504ca5..54f10df 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
@@ -22,6 +22,10 @@
     option_env!("CI").is_some()
 }
 
+pub fn hash_once<Hasher: std::hash::Hasher + Default>(thing: impl std::hash::Hash) -> u64 {
+    std::hash::BuildHasher::hash_one(&std::hash::BuildHasherDefault::<Hasher>::default(), thing)
+}
+
 #[must_use]
 #[allow(clippy::print_stderr)]
 pub fn timeit(label: &'static str) -> impl Drop {
diff --git a/src/tools/rust-analyzer/crates/stdx/src/process.rs b/src/tools/rust-analyzer/crates/stdx/src/process.rs
index e6935f0..c54d850 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/process.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/process.rs
@@ -162,7 +162,7 @@
         pipe::NamedPipe,
         Overlapped,
     };
-    use winapi::shared::winerror::ERROR_BROKEN_PIPE;
+    use windows_sys::Win32::Foundation::ERROR_BROKEN_PIPE;
 
     struct Pipe<'a> {
         dst: &'a mut Vec<u8>,
diff --git a/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml
index a235e3e..c2c6dac 100644
--- a/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml
@@ -3,7 +3,7 @@
 version = "0.0.1"
 publish = false
 edition = "2021"
-rust-version = "1.76"
+rust-version = "1.78"
 
 [package.metadata]
 cargo-fuzz = true
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index e1765b2..8c772b9 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -314,7 +314,9 @@
   '#' '!'? '[' Meta ']'
 
 Meta =
-  Path ('=' Expr | TokenTree)?
+  'unsafe' '(' Path ('=' Expr | TokenTree)? ')'
+| Path ('=' Expr | TokenTree)?
+
 
 //****************************//
 // Statements and Expressions //
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index c82bc41..98186c5 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -778,7 +778,10 @@
     pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
     pub fn path(&self) -> Option<Path> { support::child(&self.syntax) }
     pub fn token_tree(&self) -> Option<TokenTree> { support::child(&self.syntax) }
+    pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+    pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
     pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+    pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
index 7cd1f15..1659988 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
@@ -6,7 +6,7 @@
 };
 
 use rustc_lexer::unescape::{
-    unescape_byte, unescape_char, unescape_mixed, unescape_unicode, MixedUnit, Mode,
+    unescape_byte, unescape_char, unescape_mixed, unescape_unicode, EscapeError, MixedUnit, Mode,
 };
 
 use crate::{
@@ -180,10 +180,7 @@
     fn close_quote_text_range(&self) -> Option<TextRange> {
         self.quote_offsets().map(|it| it.quotes.1)
     }
-    fn escaped_char_ranges(
-        &self,
-        cb: &mut dyn FnMut(TextRange, Result<char, rustc_lexer::unescape::EscapeError>),
-    ) {
+    fn escaped_char_ranges(&self, cb: &mut dyn FnMut(TextRange, Result<char, EscapeError>)) {
         let text_range_no_quotes = match self.text_range_between_quotes() {
             Some(it) => it,
             None => return,
@@ -212,20 +209,17 @@
 }
 
 impl ast::String {
-    pub fn value(&self) -> Option<Cow<'_, str>> {
-        if self.is_raw() {
-            let text = self.text();
-            let text =
-                &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
-            return Some(Cow::Borrowed(text));
-        }
-
+    pub fn value(&self) -> Result<Cow<'_, str>, EscapeError> {
         let text = self.text();
-        let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
+        let text_range = self.text_range_between_quotes().ok_or(EscapeError::LoneSlash)?;
+        let text = &text[text_range - self.syntax().text_range().start()];
+        if self.is_raw() {
+            return Ok(Cow::Borrowed(text));
+        }
 
         let mut buf = String::new();
         let mut prev_end = 0;
-        let mut has_error = false;
+        let mut has_error = None;
         unescape_unicode(text, Self::MODE, &mut |char_range, unescaped_char| match (
             unescaped_char,
             buf.capacity() == 0,
@@ -239,13 +233,13 @@
                 buf.push_str(&text[..prev_end]);
                 buf.push(c);
             }
-            (Err(_), _) => has_error = true,
+            (Err(e), _) => has_error = Some(e),
         });
 
         match (has_error, buf.capacity() == 0) {
-            (true, _) => None,
-            (false, true) => Some(Cow::Borrowed(text)),
-            (false, false) => Some(Cow::Owned(buf)),
+            (Some(e), _) => Err(e),
+            (None, true) => Ok(Cow::Borrowed(text)),
+            (None, false) => Ok(Cow::Owned(buf)),
         }
     }
 }
@@ -256,20 +250,17 @@
 }
 
 impl ast::ByteString {
-    pub fn value(&self) -> Option<Cow<'_, [u8]>> {
-        if self.is_raw() {
-            let text = self.text();
-            let text =
-                &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
-            return Some(Cow::Borrowed(text.as_bytes()));
-        }
-
+    pub fn value(&self) -> Result<Cow<'_, [u8]>, EscapeError> {
         let text = self.text();
-        let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
+        let text_range = self.text_range_between_quotes().ok_or(EscapeError::LoneSlash)?;
+        let text = &text[text_range - self.syntax().text_range().start()];
+        if self.is_raw() {
+            return Ok(Cow::Borrowed(text.as_bytes()));
+        }
 
         let mut buf: Vec<u8> = Vec::new();
         let mut prev_end = 0;
-        let mut has_error = false;
+        let mut has_error = None;
         unescape_unicode(text, Self::MODE, &mut |char_range, unescaped_char| match (
             unescaped_char,
             buf.capacity() == 0,
@@ -283,13 +274,13 @@
                 buf.extend_from_slice(text[..prev_end].as_bytes());
                 buf.push(c as u8);
             }
-            (Err(_), _) => has_error = true,
+            (Err(e), _) => has_error = Some(e),
         });
 
         match (has_error, buf.capacity() == 0) {
-            (true, _) => None,
-            (false, true) => Some(Cow::Borrowed(text.as_bytes())),
-            (false, false) => Some(Cow::Owned(buf)),
+            (Some(e), _) => Err(e),
+            (None, true) => Ok(Cow::Borrowed(text.as_bytes())),
+            (None, false) => Ok(Cow::Owned(buf)),
         }
     }
 }
@@ -298,10 +289,7 @@
     const RAW_PREFIX: &'static str = "cr";
     const MODE: Mode = Mode::CStr;
 
-    fn escaped_char_ranges(
-        &self,
-        cb: &mut dyn FnMut(TextRange, Result<char, rustc_lexer::unescape::EscapeError>),
-    ) {
+    fn escaped_char_ranges(&self, cb: &mut dyn FnMut(TextRange, Result<char, EscapeError>)) {
         let text_range_no_quotes = match self.text_range_between_quotes() {
             Some(it) => it,
             None => return,
@@ -322,20 +310,17 @@
 }
 
 impl ast::CString {
-    pub fn value(&self) -> Option<Cow<'_, [u8]>> {
-        if self.is_raw() {
-            let text = self.text();
-            let text =
-                &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
-            return Some(Cow::Borrowed(text.as_bytes()));
-        }
-
+    pub fn value(&self) -> Result<Cow<'_, [u8]>, EscapeError> {
         let text = self.text();
-        let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
+        let text_range = self.text_range_between_quotes().ok_or(EscapeError::LoneSlash)?;
+        let text = &text[text_range - self.syntax().text_range().start()];
+        if self.is_raw() {
+            return Ok(Cow::Borrowed(text.as_bytes()));
+        }
 
         let mut buf = Vec::new();
         let mut prev_end = 0;
-        let mut has_error = false;
+        let mut has_error = None;
         let extend_unit = |buf: &mut Vec<u8>, unit: MixedUnit| match unit {
             MixedUnit::Char(c) => buf.extend(c.encode_utf8(&mut [0; 4]).as_bytes()),
             MixedUnit::HighByte(b) => buf.push(b),
@@ -353,13 +338,13 @@
                 buf.extend(text[..prev_end].as_bytes());
                 extend_unit(&mut buf, u);
             }
-            (Err(_), _) => has_error = true,
+            (Err(e), _) => has_error = Some(e),
         });
 
         match (has_error, buf.capacity() == 0) {
-            (true, _) => None,
-            (false, true) => Some(Cow::Borrowed(text.as_bytes())),
-            (false, false) => Some(Cow::Owned(buf)),
+            (Some(e), _) => Err(e),
+            (None, true) => Ok(Cow::Borrowed(text.as_bytes())),
+            (None, false) => Ok(Cow::Owned(buf)),
         }
     }
 }
@@ -478,34 +463,34 @@
 }
 
 impl ast::Char {
-    pub fn value(&self) -> Option<char> {
+    pub fn value(&self) -> Result<char, EscapeError> {
         let mut text = self.text();
         if text.starts_with('\'') {
             text = &text[1..];
         } else {
-            return None;
+            return Err(EscapeError::ZeroChars);
         }
         if text.ends_with('\'') {
             text = &text[0..text.len() - 1];
         }
 
-        unescape_char(text).ok()
+        unescape_char(text)
     }
 }
 
 impl ast::Byte {
-    pub fn value(&self) -> Option<u8> {
+    pub fn value(&self) -> Result<u8, EscapeError> {
         let mut text = self.text();
         if text.starts_with("b\'") {
             text = &text[2..];
         } else {
-            return None;
+            return Err(EscapeError::ZeroChars);
         }
         if text.ends_with('\'') {
             text = &text[0..text.len() - 1];
         }
 
-        unescape_byte(text).ok()
+        unescape_byte(text)
     }
 }
 
@@ -559,7 +544,10 @@
 
     fn check_string_value<'a>(lit: &str, expected: impl Into<Option<&'a str>>) {
         assert_eq!(
-            ast::String { syntax: make::tokens::literal(&format!("\"{lit}\"")) }.value().as_deref(),
+            ast::String { syntax: make::tokens::literal(&format!("\"{lit}\"")) }
+                .value()
+                .as_deref()
+                .ok(),
             expected.into()
         );
     }
@@ -584,7 +572,8 @@
         assert_eq!(
             ast::ByteString { syntax: make::tokens::literal(&format!("b\"{lit}\"")) }
                 .value()
-                .as_deref(),
+                .as_deref()
+                .ok(),
             expected.into().map(|value| &value[..])
         );
     }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/validation/block.rs b/src/tools/rust-analyzer/crates/syntax/src/validation/block.rs
index 8eb4a10..fe3d61b 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/validation/block.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/validation/block.rs
@@ -9,7 +9,7 @@
 pub(crate) fn validate_block_expr(block: ast::BlockExpr, errors: &mut Vec<SyntaxError>) {
     if let Some(parent) = block.syntax().parent() {
         match parent.kind() {
-            FN | EXPR_STMT | STMT_LIST => return,
+            FN | EXPR_STMT | STMT_LIST | MACRO_STMTS => return,
             _ => {}
         }
     }
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index 89ed6a6..be99611 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -240,7 +240,12 @@
                 crate_graph
                     .add_dep(
                         from_id,
-                        Dependency::with_prelude(CrateName::new(&to).unwrap(), to_id, prelude),
+                        Dependency::with_prelude(
+                            CrateName::new(&to).unwrap(),
+                            to_id,
+                            prelude,
+                            false,
+                        ),
                     )
                     .unwrap();
             }
@@ -275,7 +280,15 @@
 
             for krate in all_crates {
                 crate_graph
-                    .add_dep(krate, Dependency::new(CrateName::new("core").unwrap(), core_crate))
+                    .add_dep(
+                        krate,
+                        Dependency::with_prelude(
+                            CrateName::new("core").unwrap(),
+                            core_crate,
+                            true,
+                            true,
+                        ),
+                    )
                     .unwrap();
             }
         }
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
index f125792..0257ed9 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -28,7 +28,7 @@
 //!     env: option
 //!     eq: sized
 //!     error: fmt
-//!     fmt: option, result, transmute, coerce_unsized
+//!     fmt: option, result, transmute, coerce_unsized, copy, clone, derive
 //!     fn:
 //!     from: sized
 //!     future: pin
@@ -913,11 +913,13 @@
     }
 
     mod rt {
+        use super::*;
 
         extern "C" {
             type Opaque;
         }
 
+        #[derive(Copy, Clone)]
         #[lang = "format_argument"]
         pub struct Argument<'a> {
             value: &'a Opaque,
@@ -930,8 +932,8 @@
                 unsafe { Argument { formatter: transmute(f), value: transmute(x) } }
             }
 
-            pub fn new_display<'b, T: Display>(x: &'b T) -> Argument<'_> {
-                Self::new(x, Display::fmt)
+            pub fn new_display<'b, T: crate::fmt::Display>(x: &'b T) -> Argument<'_> {
+                Self::new(x, crate::fmt::Display::fmt)
             }
         }
 
@@ -968,7 +970,9 @@
                 flags: u32,
                 precision: Count,
                 width: Count,
-            ) -> Self;
+            ) -> Self {
+                Placeholder { position, fill, align, flags, precision, width }
+            }
         }
 
         #[lang = "format_unsafe_arg"]
@@ -977,10 +981,13 @@
         }
 
         impl UnsafeArg {
-            pub unsafe fn new() -> Self;
+            pub unsafe fn new() -> Self {
+                UnsafeArg { _private: () }
+            }
         }
     }
 
+    #[derive(Copy, Clone)]
     #[lang = "format_arguments"]
     pub struct Arguments<'a> {
         pieces: &'a [&'static str],
@@ -1005,6 +1012,14 @@
         ) -> Arguments<'a> {
             Arguments { pieces, fmt: Some(fmt), args }
         }
+
+        pub const fn as_str(&self) -> Option<&'static str> {
+            match (self.pieces, self.args) {
+                ([], []) => Some(""),
+                ([s], []) => Some(s),
+                _ => None,
+            }
+        }
     }
 
     // region:derive
@@ -1154,8 +1169,8 @@
         pointer: P,
     }
     impl<P> Pin<P> {
-        pub fn new(_pointer: P) -> Pin<P> {
-            loop {}
+        pub fn new(pointer: P) -> Pin<P> {
+            Pin { pointer }
         }
     }
     // region:deref
@@ -1356,18 +1371,48 @@
 // region:panic
 mod panic {
     pub macro panic_2021 {
-        () => (
-            $crate::panicking::panic("explicit panic")
-        ),
-        ($($t:tt)+) => (
-            $crate::panicking::panic_fmt($crate::const_format_args!($($t)+))
-        ),
+        () => ({
+            const fn panic_cold_explicit() -> ! {
+                $crate::panicking::panic_explicit()
+            }
+            panic_cold_explicit();
+        }),
+        // Special-case the single-argument case for const_panic.
+        ("{}", $arg:expr $(,)?) => ({
+            #[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval
+            #[rustc_do_not_const_check] // hooked by const-eval
+            const fn panic_cold_display<T: $crate::fmt::Display>(arg: &T) -> ! {
+                $crate::panicking::panic_display(arg)
+            }
+            panic_cold_display(&$arg);
+        }),
+        ($($t:tt)+) => ({
+            // Semicolon to prevent temporaries inside the formatting machinery from
+            // being considered alive in the caller after the panic_fmt call.
+            $crate::panicking::panic_fmt($crate::const_format_args!($($t)+));
+        }),
     }
 }
 
 mod panicking {
-    #[lang = "panic_fmt"]
-    pub const fn panic_fmt(_fmt: crate::fmt::Arguments<'_>) -> ! {
+    #[rustc_const_panic_str] // enforce a &&str argument in const-check and hook this by const-eval
+    pub const fn panic_display<T: crate::fmt::Display>(x: &T) -> ! {
+        panic_fmt(crate::format_args!("{}", *x));
+    }
+
+    // This function is used instead of panic_fmt in const eval.
+    #[lang = "const_panic_fmt"]
+    pub const fn const_panic_fmt(fmt: crate::fmt::Arguments<'_>) -> ! {
+        if let Some(msg) = fmt.as_str() {
+            // The panic_display function is hooked by const eval.
+            panic_display(&msg);
+        } else {
+            loop {}
+        }
+    }
+
+    #[lang = "panic_fmt"] // needed for const-evaluated panics
+    pub const fn panic_fmt(fmt: crate::fmt::Arguments<'_>) -> ! {
         loop {}
     }
 
@@ -1378,6 +1423,7 @@
 }
 // endregion:panic
 
+#[macro_use]
 mod macros {
     // region:panic
     #[macro_export]
@@ -1470,7 +1516,6 @@
     }
     // endregion:unimplemented
 
-
     // region:derive
     pub(crate) mod builtin {
         #[rustc_builtin_macro]
diff --git a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
index 45bb777..1dbccab 100644
--- a/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/vfs-notify/src/lib.rs
@@ -222,7 +222,7 @@
                         let depth = entry.depth();
                         let is_dir = entry.file_type().is_dir();
                         let is_file = entry.file_type().is_file();
-                        let abs_path = AbsPathBuf::try_from(entry.into_path()).unwrap();
+                        let abs_path = AbsPathBuf::try_from(entry.into_path()).ok()?;
                         if depth < 2 && is_dir {
                             self.send(make_message(abs_path.clone()));
                         }
diff --git a/src/tools/rust-analyzer/crates/vfs/Cargo.toml b/src/tools/rust-analyzer/crates/vfs/Cargo.toml
index c88f346..84f2110 100644
--- a/src/tools/rust-analyzer/crates/vfs/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/vfs/Cargo.toml
@@ -13,6 +13,7 @@
 
 [dependencies]
 rustc-hash.workspace = true
+tracing.workspace = true
 fst = "0.4.7"
 indexmap.workspace = true
 nohash-hasher.workspace = true
@@ -21,4 +22,4 @@
 stdx.workspace = true
 
 [lints]
-workspace = true
\ No newline at end of file
+workspace = true
diff --git a/src/tools/rust-analyzer/crates/vfs/src/lib.rs b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
index ddd6bbe..b07e97c 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/lib.rs
@@ -46,7 +46,7 @@
 mod path_interner;
 mod vfs_path;
 
-use std::{fmt, mem};
+use std::{fmt, hash::BuildHasherDefault, mem};
 
 use crate::path_interner::PathInterner;
 
@@ -54,8 +54,13 @@
     anchored_path::{AnchoredPath, AnchoredPathBuf},
     vfs_path::VfsPath,
 };
+use indexmap::{map::Entry, IndexMap};
 pub use paths::{AbsPath, AbsPathBuf};
 
+use rustc_hash::FxHasher;
+use stdx::hash_once;
+use tracing::{span, Level};
+
 /// Handle to a file in [`Vfs`]
 ///
 /// Most functions in rust-analyzer use this when they need to refer to a file.
@@ -91,20 +96,13 @@
 pub struct Vfs {
     interner: PathInterner,
     data: Vec<FileState>,
-    // FIXME: This should be a HashMap<FileId, ChangeFile>
-    // right now we do a nasty deduplication in GlobalState::process_changes that would be a lot
-    // easier to handle here on insertion.
-    changes: Vec<ChangedFile>,
-    // The above FIXME would then also get rid of this probably
-    created_this_cycle: Vec<FileId>,
+    changes: IndexMap<FileId, ChangedFile, BuildHasherDefault<FxHasher>>,
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
 pub enum FileState {
-    /// The file has been created this cycle.
-    Created,
-    /// The file exists.
-    Exists,
+    /// The file exists with the given content hash.
+    Exists(u64),
     /// The file is deleted.
     Deleted,
 }
@@ -127,23 +125,23 @@
     /// Returns `true` if the change is [`Create`](ChangeKind::Create) or
     /// [`Delete`](Change::Delete).
     pub fn is_created_or_deleted(&self) -> bool {
-        matches!(self.change, Change::Create(_) | Change::Delete)
+        matches!(self.change, Change::Create(_, _) | Change::Delete)
     }
 
     /// Returns `true` if the change is [`Create`](ChangeKind::Create).
     pub fn is_created(&self) -> bool {
-        matches!(self.change, Change::Create(_))
+        matches!(self.change, Change::Create(_, _))
     }
 
     /// Returns `true` if the change is [`Modify`](ChangeKind::Modify).
     pub fn is_modified(&self) -> bool {
-        matches!(self.change, Change::Modify(_))
+        matches!(self.change, Change::Modify(_, _))
     }
 
     pub fn kind(&self) -> ChangeKind {
         match self.change {
-            Change::Create(_) => ChangeKind::Create,
-            Change::Modify(_) => ChangeKind::Modify,
+            Change::Create(_, _) => ChangeKind::Create,
+            Change::Modify(_, _) => ChangeKind::Modify,
             Change::Delete => ChangeKind::Delete,
         }
     }
@@ -153,9 +151,9 @@
 #[derive(Eq, PartialEq, Debug)]
 pub enum Change {
     /// The file was (re-)created
-    Create(Vec<u8>),
+    Create(Vec<u8>, u64),
     /// The file was modified
-    Modify(Vec<u8>),
+    Modify(Vec<u8>, u64),
     /// The file was deleted
     Delete,
 }
@@ -174,9 +172,7 @@
 impl Vfs {
     /// Id of the given path if it exists in the `Vfs` and is not deleted.
     pub fn file_id(&self, path: &VfsPath) -> Option<FileId> {
-        self.interner
-            .get(path)
-            .filter(|&it| matches!(self.get(it), FileState::Exists | FileState::Created))
+        self.interner.get(path).filter(|&it| matches!(self.get(it), FileState::Exists(_)))
     }
 
     /// File path corresponding to the given `file_id`.
@@ -194,9 +190,7 @@
     pub fn iter(&self) -> impl Iterator<Item = (FileId, &VfsPath)> + '_ {
         (0..self.data.len())
             .map(|it| FileId(it as u32))
-            .filter(move |&file_id| {
-                matches!(self.get(file_id), FileState::Exists | FileState::Created)
-            })
+            .filter(move |&file_id| matches!(self.get(file_id), FileState::Exists(_)))
             .map(move |file_id| {
                 let path = self.interner.lookup(file_id);
                 (file_id, path)
@@ -210,44 +204,79 @@
     /// If the path does not currently exists in the `Vfs`, allocates a new
     /// [`FileId`] for it.
     pub fn set_file_contents(&mut self, path: VfsPath, contents: Option<Vec<u8>>) -> bool {
+        let _p = span!(Level::INFO, "Vfs::set_file_contents").entered();
         let file_id = self.alloc_file_id(path);
         let state = self.get(file_id);
         let change_kind = match (state, contents) {
             (FileState::Deleted, None) => return false,
-            (FileState::Deleted, Some(v)) => Change::Create(v),
-            (FileState::Exists | FileState::Created, None) => Change::Delete,
-            (FileState::Exists | FileState::Created, Some(v)) => Change::Modify(v),
-        };
-        self.data[file_id.0 as usize] = match change_kind {
-            Change::Create(_) => {
-                self.created_this_cycle.push(file_id);
-                FileState::Created
+            (FileState::Deleted, Some(v)) => {
+                let hash = hash_once::<FxHasher>(&*v);
+                Change::Create(v, hash)
             }
-            // If the file got created this cycle, make sure we keep it that way even
-            // if a modify comes in
-            Change::Modify(_) if matches!(state, FileState::Created) => FileState::Created,
-            Change::Modify(_) => FileState::Exists,
-            Change::Delete => FileState::Deleted,
+            (FileState::Exists(_), None) => Change::Delete,
+            (FileState::Exists(hash), Some(v)) => {
+                let new_hash = hash_once::<FxHasher>(&*v);
+                if new_hash == hash {
+                    return false;
+                }
+                Change::Modify(v, new_hash)
+            }
         };
+
+        let mut set_data = |change_kind| {
+            self.data[file_id.0 as usize] = match change_kind {
+                &Change::Create(_, hash) | &Change::Modify(_, hash) => FileState::Exists(hash),
+                Change::Delete => FileState::Deleted,
+            };
+        };
+
         let changed_file = ChangedFile { file_id, change: change_kind };
-        self.changes.push(changed_file);
+        match self.changes.entry(file_id) {
+            // two changes to the same file in one cycle, merge them appropriately
+            Entry::Occupied(mut o) => {
+                use Change::*;
+
+                match (&mut o.get_mut().change, changed_file.change) {
+                    // newer `Delete` wins
+                    (change, Delete) => *change = Delete,
+                    // merge `Create` with `Create` or `Modify`
+                    (Create(prev, old_hash), Create(new, new_hash) | Modify(new, new_hash)) => {
+                        *prev = new;
+                        *old_hash = new_hash;
+                    }
+                    // collapse identical `Modify`es
+                    (Modify(prev, old_hash), Modify(new, new_hash)) => {
+                        *prev = new;
+                        *old_hash = new_hash;
+                    }
+                    // equivalent to `Modify`
+                    (change @ Delete, Create(new, new_hash)) => {
+                        *change = Modify(new, new_hash);
+                    }
+                    // shouldn't occur, but collapse into `Create`
+                    (change @ Delete, Modify(new, new_hash)) => {
+                        stdx::never!();
+                        *change = Create(new, new_hash);
+                    }
+                    // shouldn't occur, but keep the Create
+                    (prev @ Modify(_, _), new @ Create(_, _)) => *prev = new,
+                }
+                set_data(&o.get().change);
+            }
+            Entry::Vacant(v) => set_data(&v.insert(changed_file).change),
+        };
+
         true
     }
 
     /// Drain and returns all the changes in the `Vfs`.
-    pub fn take_changes(&mut self) -> Vec<ChangedFile> {
-        for file_id in self.created_this_cycle.drain(..) {
-            if self.data[file_id.0 as usize] == FileState::Created {
-                // downgrade the file from `Created` to `Exists` as the cycle is done
-                self.data[file_id.0 as usize] = FileState::Exists;
-            }
-        }
+    pub fn take_changes(&mut self) -> IndexMap<FileId, ChangedFile, BuildHasherDefault<FxHasher>> {
         mem::take(&mut self.changes)
     }
 
     /// Provides a panic-less way to verify file_id validity.
     pub fn exists(&self, file_id: FileId) -> bool {
-        matches!(self.get(file_id), FileState::Exists | FileState::Created)
+        matches!(self.get(file_id), FileState::Exists(_))
     }
 
     /// Returns the id associated with `path`
diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md
index cdab6b0..8897f02 100644
--- a/src/tools/rust-analyzer/docs/dev/README.md
+++ b/src/tools/rust-analyzer/docs/dev/README.md
@@ -229,12 +229,22 @@
      * publishes the VS Code extension to the marketplace
    * call the GitHub API for PR details
    * create a new changelog in `rust-analyzer.github.io`
-3. While the release is in progress, fill in the changelog
-4. Commit & push the changelog
+3. While the release is in progress, fill in the changelog.
+4. Commit & push the changelog.
 5. Run `cargo xtask publish-release-notes <CHANGELOG>` -- this will convert the changelog entry in AsciiDoc to Markdown and update the body of GitHub Releases entry.
-6. Tweet
-7. Inside `rust-analyzer`, run `cargo xtask promote` -- this will create a PR to rust-lang/rust updating rust-analyzer's subtree.
-   Self-approve the PR.
+6. Tweet.
+7. Make a new branch and run `cargo xtask rustc-pull`, open a PR, and merge it.
+   This will pull any changes from `rust-lang/rust` into `rust-analyzer`.
+8. Switch to `master`, pull, then run `cargo xtask rustc-push --rust-path ../rust-rust-analyzer --rust-fork matklad/rust`.
+   Replace `matklad/rust` with your own fork of `rust-lang/rust`.
+   You can use the token to authenticate when you get prompted for a password, since `josh` will push over HTTPS, not SSH.
+   This will push the `rust-analyzer` changes to your fork.
+   You can then open a PR against `rust-lang/rust`.
+
+Note: besides the `rust-rust-analyzer` clone, the Josh cache (stored under `~/.cache/rust-analyzer-josh`) will contain a bare clone of `rust-lang/rust`.
+This currently takes about 3.5 GB.
+
+This [HackMD](https://hackmd.io/7pOuxnkdQDaL1Y1FQr65xg) has details about how `josh` syncs work.
 
 If the GitHub Actions release fails because of a transient problem like a timeout, you can re-run the job from the Actions console.
 If it fails because of something that needs to be fixed, remove the release tag (if needed), fix the problem, then start over.
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index f181508..46c1ccb 100644
--- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
+++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
 <!---
-lsp/ext.rs hash: dd51139b0530147e
+lsp/ext.rs hash: a39009c351009d16
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue:
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index a03ab00..8993a46 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -9,6 +9,11 @@
 --
 Placeholder expression to use for missing expressions in assists.
 --
+[[rust-analyzer.assist.termSearch.fuel]]rust-analyzer.assist.termSearch.fuel (default: `400`)::
++
+--
+Term search fuel in "units of work" for assists (Defaults to 400).
+--
 [[rust-analyzer.cachePriming.enable]]rust-analyzer.cachePriming.enable (default: `true`)::
 +
 --
@@ -256,7 +261,7 @@
 If `$saved_file` is part of the command, rust-analyzer will pass
 the absolute path of the saved file to the provided command. This is
 intended to be used with non-Cargo build systems.
-Note that `$saved_file` is experimental and may be removed in the futureg.
+Note that `$saved_file` is experimental and may be removed in the future.
 
 An example command would be:
 
@@ -373,6 +378,11 @@
 --
 Whether to enable term search based snippets like `Some(foo.bar().baz())`.
 --
+[[rust-analyzer.completion.termSearch.fuel]]rust-analyzer.completion.termSearch.fuel (default: `200`)::
++
+--
+Term search fuel in "units of work" for autocompletion (Defaults to 200).
+--
 [[rust-analyzer.diagnostics.disabled]]rust-analyzer.diagnostics.disabled (default: `[]`)::
 +
 --
@@ -529,10 +539,15 @@
 --
 How to render the size information in a memory layout hover.
 --
-[[rust-analyzer.hover.show.structFields]]rust-analyzer.hover.show.structFields (default: `null`)::
+[[rust-analyzer.hover.show.enumVariants]]rust-analyzer.hover.show.enumVariants (default: `5`)::
 +
 --
-How many fields of a struct to display when hovering a struct.
+How many variants of an enum to display when hovering on. Show none if empty.
+--
+[[rust-analyzer.hover.show.fields]]rust-analyzer.hover.show.fields (default: `5`)::
++
+--
+How many fields of a struct, variant or union to display when hovering on. Show none if empty.
 --
 [[rust-analyzer.hover.show.traitAssocItems]]rust-analyzer.hover.show.traitAssocItems (default: `null`)::
 +
@@ -778,7 +793,8 @@
 of projects.
 
 Elements must be paths pointing to `Cargo.toml`,
-`rust-project.json`, or JSON objects in `rust-project.json` format.
+`rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON
+objects in `rust-project.json` format.
 --
 [[rust-analyzer.lru.capacity]]rust-analyzer.lru.capacity (default: `null`)::
 +
diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc
index 6521b6d..8e6c53d 100644
--- a/src/tools/rust-analyzer/docs/user/manual.adoc
+++ b/src/tools/rust-analyzer/docs/user/manual.adoc
@@ -376,7 +376,7 @@
 ----
 lspconfig.rust_analyzer.setup({
     on_attach = function(client, bufnr)
-        vim.lsp.inlay_hint.enable(bufnr)
+        vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
     end
 })
 ----
@@ -787,8 +787,6 @@
 
 Relative paths are interpreted relative to `rust-project.json` file location or (for inline JSON) relative to `rootUri`.
 
-See https://github.com/rust-analyzer/rust-project.json-example for a small example.
-
 You can set the `RA_LOG` environment variable to `rust_analyzer=info` to inspect how rust-analyzer handles config and project loading.
 
 Note that calls to `cargo check` are disabled when using `rust-project.json` by default, so compilation errors and warnings will no longer be sent to your LSP client.
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 389e1b8..6e4fedd 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -534,6 +534,12 @@
                         "Fill missing expressions with reasonable defaults, `new` or `default` constructors."
                     ]
                 },
+                "rust-analyzer.assist.termSearch.fuel": {
+                    "markdownDescription": "Term search fuel in \"units of work\" for assists (Defaults to 400).",
+                    "default": 400,
+                    "type": "integer",
+                    "minimum": 0
+                },
                 "rust-analyzer.cachePriming.enable": {
                     "markdownDescription": "Warm up caches on project load.",
                     "default": true,
@@ -798,7 +804,7 @@
                     ]
                 },
                 "rust-analyzer.check.overrideCommand": {
-                    "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option\n(if your client supports the `colorDiagnosticOutput` experimental\ncapability, you can use `--message-format=json-diagnostic-rendered-ansi`).\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects/workspaces, this command is invoked for\neach of them, with the working directory being the workspace root\n(i.e., the folder containing the `Cargo.toml`). This can be overwritten\nby changing `#rust-analyzer.check.invocationStrategy#` and\n`#rust-analyzer.check.invocationLocation#`.\n\nIf `$saved_file` is part of the command, rust-analyzer will pass\nthe absolute path of the saved file to the provided command. This is\nintended to be used with non-Cargo build systems.\nNote that `$saved_file` is experimental and may be removed in the futureg.\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.",
+                    "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option\n(if your client supports the `colorDiagnosticOutput` experimental\ncapability, you can use `--message-format=json-diagnostic-rendered-ansi`).\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects/workspaces, this command is invoked for\neach of them, with the working directory being the workspace root\n(i.e., the folder containing the `Cargo.toml`). This can be overwritten\nby changing `#rust-analyzer.check.invocationStrategy#` and\n`#rust-analyzer.check.invocationLocation#`.\n\nIf `$saved_file` is part of the command, rust-analyzer will pass\nthe absolute path of the saved file to the provided command. This is\nintended to be used with non-Cargo build systems.\nNote that `$saved_file` is experimental and may be removed in the future.\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.",
                     "default": null,
                     "type": [
                         "null",
@@ -930,6 +936,12 @@
                     "default": false,
                     "type": "boolean"
                 },
+                "rust-analyzer.completion.termSearch.fuel": {
+                    "markdownDescription": "Term search fuel in \"units of work\" for autocompletion (Defaults to 200).",
+                    "default": 200,
+                    "type": "integer",
+                    "minimum": 0
+                },
                 "rust-analyzer.diagnostics.disabled": {
                     "markdownDescription": "List of rust-analyzer diagnostics to disable.",
                     "default": [],
@@ -1145,9 +1157,18 @@
                         }
                     ]
                 },
-                "rust-analyzer.hover.show.structFields": {
-                    "markdownDescription": "How many fields of a struct to display when hovering a struct.",
-                    "default": null,
+                "rust-analyzer.hover.show.enumVariants": {
+                    "markdownDescription": "How many variants of an enum to display when hovering on. Show none if empty.",
+                    "default": 5,
+                    "type": [
+                        "null",
+                        "integer"
+                    ],
+                    "minimum": 0
+                },
+                "rust-analyzer.hover.show.fields": {
+                    "markdownDescription": "How many fields of a struct, variant or union to display when hovering on. Show none if empty.",
+                    "default": 5,
                     "type": [
                         "null",
                         "integer"
@@ -1495,7 +1516,7 @@
                     "type": "boolean"
                 },
                 "rust-analyzer.linkedProjects": {
-                    "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, or JSON objects in `rust-project.json` format.",
+                    "markdownDescription": "Disable project auto-discovery in favor of explicitly specified set\nof projects.\n\nElements must be paths pointing to `Cargo.toml`,\n`rust-project.json`, `.rs` files (which will be treated as standalone files) or JSON\nobjects in `rust-project.json` format.",
                     "default": [],
                     "type": "array",
                     "items": {
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index f76dec2..5b683dc 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -433,7 +433,6 @@
         statusBar.tooltip.isTrusted = true;
         switch (status.health) {
             case "ok":
-                statusBar.tooltip.appendText(status.message ?? "Ready");
                 statusBar.color = undefined;
                 statusBar.backgroundColor = undefined;
                 if (this.config.statusBarClickAction === "stopServer") {
@@ -444,9 +443,6 @@
                 this.dependencies?.refresh();
                 break;
             case "warning":
-                if (status.message) {
-                    statusBar.tooltip.appendText(status.message);
-                }
                 statusBar.color = new vscode.ThemeColor("statusBarItem.warningForeground");
                 statusBar.backgroundColor = new vscode.ThemeColor(
                     "statusBarItem.warningBackground",
@@ -455,9 +451,6 @@
                 icon = "$(warning) ";
                 break;
             case "error":
-                if (status.message) {
-                    statusBar.tooltip.appendText(status.message);
-                }
                 statusBar.color = new vscode.ThemeColor("statusBarItem.errorForeground");
                 statusBar.backgroundColor = new vscode.ThemeColor("statusBarItem.errorBackground");
                 statusBar.command = "rust-analyzer.openLogs";
@@ -476,6 +469,15 @@
                 statusBar.text = "$(stop-circle) rust-analyzer";
                 return;
         }
+        if (status.message) {
+            statusBar.tooltip.appendText(status.message);
+        }
+        if (status.workspaceInfo) {
+            if (statusBar.tooltip.value) {
+                statusBar.tooltip.appendMarkdown("\n\n---\n\n");
+            }
+            statusBar.tooltip.appendMarkdown(status.workspaceInfo);
+        }
         if (statusBar.tooltip.value) {
             statusBar.tooltip.appendMarkdown("\n\n---\n\n");
         }
diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
index 9a7a4aa..7d6b16b 100644
--- a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
+++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
@@ -241,6 +241,7 @@
     health: "ok" | "warning" | "error";
     quiescent: boolean;
     message?: string;
+    workspaceInfo?: string;
 };
 export type SsrParams = {
     query: string;
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
index 71e5933..53c6479 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
@@ -153,6 +153,14 @@
     pub params: serde_json::Value,
 }
 
+fn invalid_data(error: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Error {
+    io::Error::new(io::ErrorKind::InvalidData, error)
+}
+
+macro_rules! invalid_data {
+    ($($tt:tt)*) => (invalid_data(format!($($tt)*)))
+}
+
 impl Message {
     pub fn read(r: &mut impl BufRead) -> io::Result<Option<Message>> {
         Message::_read(r)
@@ -162,7 +170,14 @@
             None => return Ok(None),
             Some(text) => text,
         };
-        let msg = serde_json::from_str(&text)?;
+
+        let msg = match serde_json::from_str(&text) {
+            Ok(msg) => msg,
+            Err(e) => {
+                return Err(invalid_data!("malformed LSP payload: {:?}", e));
+            }
+        };
+
         Ok(Some(msg))
     }
     pub fn write(self, w: &mut impl Write) -> io::Result<()> {
@@ -240,13 +255,6 @@
 }
 
 fn read_msg_text(inp: &mut dyn BufRead) -> io::Result<Option<String>> {
-    fn invalid_data(error: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> io::Error {
-        io::Error::new(io::ErrorKind::InvalidData, error)
-    }
-    macro_rules! invalid_data {
-        ($($tt:tt)*) => (invalid_data(format!($($tt)*)))
-    }
-
     let mut size = None;
     let mut buf = String::new();
     loop {
@@ -264,12 +272,12 @@
         let mut parts = buf.splitn(2, ": ");
         let header_name = parts.next().unwrap();
         let header_value =
-            parts.next().ok_or_else(|| invalid_data(format!("malformed header: {:?}", buf)))?;
+            parts.next().ok_or_else(|| invalid_data!("malformed header: {:?}", buf))?;
         if header_name.eq_ignore_ascii_case("Content-Length") {
             size = Some(header_value.parse::<usize>().map_err(invalid_data)?);
         }
     }
-    let size: usize = size.ok_or_else(|| invalid_data("no Content-Length".to_owned()))?;
+    let size: usize = size.ok_or_else(|| invalid_data!("no Content-Length"))?;
     let mut buf = buf.into_bytes();
     buf.resize(size, 0);
     inp.read_exact(&mut buf)?;
diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version
new file mode 100644
index 0000000..207ef6c
--- /dev/null
+++ b/src/tools/rust-analyzer/rust-version
@@ -0,0 +1 @@
+6579ed89f0fcc26da71afdd11d30d63f6f812a0a
diff --git a/src/tools/rust-analyzer/xtask/Cargo.toml b/src/tools/rust-analyzer/xtask/Cargo.toml
index a83d32e..192de86 100644
--- a/src/tools/rust-analyzer/xtask/Cargo.toml
+++ b/src/tools/rust-analyzer/xtask/Cargo.toml
@@ -8,6 +8,7 @@
 
 [dependencies]
 anyhow.workspace = true
+directories = "5.0"
 flate2 = "1.0.24"
 write-json = "0.1.2"
 xshell.workspace = true
diff --git a/src/tools/rust-analyzer/xtask/src/flags.rs b/src/tools/rust-analyzer/xtask/src/flags.rs
index 9066545..dd7bfd0 100644
--- a/src/tools/rust-analyzer/xtask/src/flags.rs
+++ b/src/tools/rust-analyzer/xtask/src/flags.rs
@@ -14,16 +14,16 @@
         cmd install {
             /// Install only VS Code plugin.
             optional --client
-            /// One of 'code', 'code-exploration', 'code-insiders', 'codium', or 'code-oss'.
+            /// One of `code`, `code-exploration`, `code-insiders`, `codium`, or `code-oss`.
             optional --code-bin name: String
 
             /// Install only the language server.
             optional --server
-            /// Use mimalloc allocator for server
+            /// Use mimalloc allocator for server.
             optional --mimalloc
-            /// Use jemalloc allocator for server
+            /// Use jemalloc allocator for server.
             optional --jemalloc
-            /// build in release with debug info set to 2
+            /// build in release with debug info set to 2.
             optional --dev-rel
         }
 
@@ -32,9 +32,21 @@
         cmd release {
             optional --dry-run
         }
-        cmd promote {
-            optional --dry-run
+
+        cmd rustc-pull {
+            /// rustc commit to pull.
+            optional --commit refspec: String
         }
+
+        cmd rustc-push {
+            /// rust local path, e.g. `../rust-rust-analyzer`.
+            required --rust-path rust_path: String
+            /// rust fork name, e.g.  `matklad/rust`.
+            required --rust-fork rust_fork: String
+            /// branch name.
+            optional --branch branch: String
+        }
+
         cmd dist {
             /// Use mimalloc allocator for server
             optional --mimalloc
@@ -77,7 +89,8 @@
     Install(Install),
     FuzzTests(FuzzTests),
     Release(Release),
-    Promote(Promote),
+    RustcPull(RustcPull),
+    RustcPush(RustcPush),
     Dist(Dist),
     PublishReleaseNotes(PublishReleaseNotes),
     Metrics(Metrics),
@@ -104,8 +117,15 @@
 }
 
 #[derive(Debug)]
-pub struct Promote {
-    pub dry_run: bool,
+pub struct RustcPull {
+    pub commit: Option<String>,
+}
+
+#[derive(Debug)]
+pub struct RustcPush {
+    pub rust_path: String,
+    pub rust_fork: String,
+    pub branch: Option<String>,
 }
 
 #[derive(Debug)]
diff --git a/src/tools/rust-analyzer/xtask/src/main.rs b/src/tools/rust-analyzer/xtask/src/main.rs
index 9418675..e070576 100644
--- a/src/tools/rust-analyzer/xtask/src/main.rs
+++ b/src/tools/rust-analyzer/xtask/src/main.rs
@@ -34,7 +34,8 @@
         flags::XtaskCmd::Install(cmd) => cmd.run(sh),
         flags::XtaskCmd::FuzzTests(_) => run_fuzzer(sh),
         flags::XtaskCmd::Release(cmd) => cmd.run(sh),
-        flags::XtaskCmd::Promote(cmd) => cmd.run(sh),
+        flags::XtaskCmd::RustcPull(cmd) => cmd.run(sh),
+        flags::XtaskCmd::RustcPush(cmd) => cmd.run(sh),
         flags::XtaskCmd::Dist(cmd) => cmd.run(sh),
         flags::XtaskCmd::PublishReleaseNotes(cmd) => cmd.run(sh),
         flags::XtaskCmd::Metrics(cmd) => cmd.run(sh),
diff --git a/src/tools/rust-analyzer/xtask/src/release.rs b/src/tools/rust-analyzer/xtask/src/release.rs
index 1a5e6df..5699053 100644
--- a/src/tools/rust-analyzer/xtask/src/release.rs
+++ b/src/tools/rust-analyzer/xtask/src/release.rs
@@ -1,5 +1,12 @@
 mod changelog;
 
+use std::process::{Command, Stdio};
+use std::thread;
+use std::time::Duration;
+
+use anyhow::{bail, Context as _};
+use directories::ProjectDirs;
+use stdx::JodChild;
 use xshell::{cmd, Shell};
 
 use crate::{codegen, date_iso, flags, is_release_tag, project_root};
@@ -71,26 +78,167 @@
     }
 }
 
-impl flags::Promote {
+// git sync implementation adapted from https://github.com/rust-lang/miri/blob/62039ac/miri-script/src/commands.rs
+impl flags::RustcPull {
     pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
-        let _dir = sh.push_dir("../rust-rust-analyzer");
-        cmd!(sh, "git switch master").run()?;
-        cmd!(sh, "git fetch upstream").run()?;
-        cmd!(sh, "git reset --hard upstream/master").run()?;
-
-        let date = date_iso(sh)?;
-        let branch = format!("rust-analyzer-{date}");
-        cmd!(sh, "git switch -c {branch}").run()?;
-        cmd!(sh, "git subtree pull -m ':arrow_up: rust-analyzer' -P src/tools/rust-analyzer rust-analyzer release").run()?;
-
-        if !self.dry_run {
-            cmd!(sh, "git push -u origin {branch}").run()?;
-            cmd!(
-                sh,
-                "xdg-open https://github.com/matklad/rust/pull/new/{branch}?body=r%3F%20%40ghost"
-            )
-            .run()?;
+        sh.change_dir(project_root());
+        let commit = self.commit.map(Result::Ok).unwrap_or_else(|| {
+            let rust_repo_head =
+                cmd!(sh, "git ls-remote https://github.com/rust-lang/rust/ HEAD").read()?;
+            rust_repo_head
+                .split_whitespace()
+                .next()
+                .map(|front| front.trim().to_owned())
+                .ok_or_else(|| anyhow::format_err!("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() {
+            bail!("working directory must be clean before running `cargo xtask pull`");
         }
+        // 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()?;
+        // Make sure josh is running.
+        let josh = start_josh()?;
+
+        // 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 any git hooks that might exist,
+        // in case they dirty the repository.
+        sh.write_file("rust-version", format!("{commit}\n"))?;
+        const PREPARING_COMMIT_MESSAGE: &str = "Preparing for merge from rust-lang/rust";
+        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 http://localhost:{JOSH_PORT}/rust-lang/rust.git@{commit}{JOSH_FILTER}.git")
+            .run()
+            .map_err(|e| {
+                // Try to un-do the previous `git commit`, to leave the repo in the state we found it it.
+                cmd!(sh, "git reset --hard HEAD^")
+                    .run()
+                    .expect("FAILED to clean up again after failed `git fetch`, sorry for that");
+                e
+            })
+            .context("FAILED to fetch new commits, something went wrong (committing the rust-version file has been undone)")?;
+
+        // Merge the fetched commit.
+        const MERGE_COMMIT_MESSAGE: &str = "Merge from rust-lang/rust";
+        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(())
     }
 }
+
+impl flags::RustcPush {
+    pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
+        let branch = self.branch.as_deref().unwrap_or("sync-from-ra");
+        let rust_path = self.rust_path;
+        let rust_fork = self.rust_fork;
+
+        sh.change_dir(project_root());
+        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() {
+            bail!("working directory must be clean before running `cargo xtask push`");
+        }
+        // Make sure josh is running.
+        let josh = start_josh()?;
+
+        // Find a repo we can do our preparation in.
+        sh.change_dir(rust_path);
+
+        // 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 {rust_fork} (base: {base})...");
+        if cmd!(sh, "git fetch https://github.com/{rust_fork} {branch}")
+            .ignore_stderr()
+            .read()
+            .is_ok()
+        {
+            bail!(
+                "The branch `{branch}` seems to already exist in `https://github.com/{rust_fork}`. Please delete it and try again."
+            );
+        }
+        cmd!(sh, "git fetch https://github.com/rust-lang/rust {base}").run()?;
+        cmd!(sh, "git push https://github.com/{rust_fork} {base}:refs/heads/{branch}")
+            .ignore_stdout()
+            .ignore_stderr() // silence the "create GitHub PR" message
+            .run()?;
+        println!();
+
+        // Do the actual push.
+        sh.change_dir(project_root());
+        println!("Pushing rust-analyzer changes...");
+        cmd!(
+            sh,
+            "git push http://localhost:{JOSH_PORT}/{rust_fork}.git{JOSH_FILTER}.git HEAD:{branch}"
+        )
+        .run()?;
+        println!();
+
+        // Do a round-trip check to make sure the push worked as expected.
+        cmd!(
+            sh,
+            "git fetch http://localhost:{JOSH_PORT}/{rust_fork}.git{JOSH_FILTER}.git {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!");
+        }
+        println!("Confirmed that the push round-trips back to rust-analyzer properly. Please create a rustc PR:");
+        // https://github.com/github-linguist/linguist/compare/master...octocat:linguist:master
+        let fork_path = rust_fork.replace('/', ":");
+        println!(
+            "    https://github.com/rust-lang/rust/compare/{fork_path}:{branch}?quick_pull=1&title=Subtree+update+of+rust-analyzer&body=r?+@ghost"
+        );
+
+        drop(josh);
+        Ok(())
+    }
+}
+
+/// Used for rustc syncs.
+const JOSH_FILTER: &str =
+    ":rev(55d9a533b309119c8acd13061581b43ae8840823:prefix=src/tools/rust-analyzer):/src/tools/rust-analyzer";
+const JOSH_PORT: &str = "42042";
+
+fn start_josh() -> anyhow::Result<impl Drop> {
+    // Determine cache directory.
+    let local_dir = {
+        let user_dirs = ProjectDirs::from("org", "rust-lang", "rust-analyzer-josh").unwrap();
+        user_dirs.cache_dir().to_owned()
+    };
+
+    // Start josh, silencing its output.
+    let mut cmd = Command::new("josh-proxy");
+    cmd.arg("--local").arg(local_dir);
+    cmd.arg("--remote").arg("https://github.com");
+    cmd.arg("--port").arg(JOSH_PORT);
+    cmd.arg("--no-background");
+    cmd.stdout(Stdio::null());
+    cmd.stderr(Stdio::null());
+    let josh = cmd.spawn().context("failed to start josh-proxy, make sure it is installed")?;
+    // Give it some time so hopefully the port is open. (100ms was not enough.)
+    thread::sleep(Duration::from_millis(200));
+
+    Ok(JodChild(josh))
+}
diff --git a/src/tools/rustc-perf b/src/tools/rustc-perf
new file mode 160000
index 0000000..4f313ad
--- /dev/null
+++ b/src/tools/rustc-perf
@@ -0,0 +1 @@
+Subproject commit 4f313add609f43e928e98132358e8426ed3969ae
diff --git a/src/tools/rustfmt/src/imports.rs b/src/tools/rustfmt/src/imports.rs
index 09f6e75..2da7462 100644
--- a/src/tools/rustfmt/src/imports.rs
+++ b/src/tools/rustfmt/src/imports.rs
@@ -458,7 +458,9 @@
                     version,
                 });
             }
-            UseTreeKind::Nested(ref list) => {
+            UseTreeKind::Nested {
+                items: ref list, ..
+            } => {
                 // Extract comments between nested use items.
                 // This needs to be done before sorting use items.
                 let items = itemize_list(
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index e196d18..e869787 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -247,7 +247,7 @@
 #[allow(dead_code)]
 #[derive(Debug)]
 struct Item<'a> {
-    unsafety: ast::Unsafe,
+    safety: ast::Safety,
     abi: Cow<'static, str>,
     vis: Option<&'a ast::Visibility>,
     body: Vec<BodyElement<'a>>,
@@ -257,7 +257,7 @@
 impl<'a> Item<'a> {
     fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
         Item {
-            unsafety: fm.unsafety,
+            safety: fm.safety,
             abi: format_extern(
                 ast::Extern::from_abi(fm.abi, DUMMY_SP),
                 config.force_explicit_abi(),
@@ -290,7 +290,7 @@
     coroutine_kind: Cow<'a, Option<ast::CoroutineKind>>,
     constness: ast::Const,
     defaultness: ast::Defaultness,
-    unsafety: ast::Unsafe,
+    safety: ast::Safety,
     visibility: &'a ast::Visibility,
 }
 
@@ -301,7 +301,7 @@
         visibility: &'a ast::Visibility,
     ) -> FnSig<'a> {
         FnSig {
-            unsafety: method_sig.header.unsafety,
+            safety: method_sig.header.safety,
             coroutine_kind: Cow::Borrowed(&method_sig.header.coroutine_kind),
             constness: method_sig.header.constness,
             defaultness: ast::Defaultness::Final,
@@ -330,7 +330,7 @@
                 constness: fn_sig.header.constness,
                 coroutine_kind: Cow::Borrowed(&fn_sig.header.coroutine_kind),
                 defaultness,
-                unsafety: fn_sig.header.unsafety,
+                safety: fn_sig.header.safety,
                 visibility: vis,
             },
             _ => unreachable!(),
@@ -345,7 +345,7 @@
         result.push_str(format_constness(self.constness));
         self.coroutine_kind
             .map(|coroutine_kind| result.push_str(format_coro(&coroutine_kind)));
-        result.push_str(format_unsafety(self.unsafety));
+        result.push_str(format_safety(self.safety));
         result.push_str(&format_extern(
             self.ext,
             context.config.force_explicit_abi(),
@@ -356,7 +356,7 @@
 
 impl<'a> FmtVisitor<'a> {
     fn format_item(&mut self, item: &Item<'_>) {
-        self.buffer.push_str(format_unsafety(item.unsafety));
+        self.buffer.push_str(format_safety(item.safety));
         self.buffer.push_str(&item.abi);
 
         let snippet = self.snippet(item.span);
@@ -739,8 +739,8 @@
                 (_, Const(..)) => Ordering::Greater,
                 (MacCall(..), _) => Ordering::Less,
                 (_, MacCall(..)) => Ordering::Greater,
-                (Delegation(..), _) => Ordering::Less,
-                (_, Delegation(..)) => Ordering::Greater,
+                (Delegation(..), _) | (DelegationMac(..), _) => Ordering::Less,
+                (_, Delegation(..)) | (_, DelegationMac(..)) => Ordering::Greater,
             });
             let mut prev_kind = None;
             for (buf, item) in buffer {
@@ -924,7 +924,7 @@
     offset: Indent,
 ) -> Option<String> {
     let ast::Impl {
-        unsafety,
+        safety,
         polarity,
         defaultness,
         constness,
@@ -937,7 +937,7 @@
 
     result.push_str(&format_visibility(context, &item.vis));
     result.push_str(format_defaultness(defaultness));
-    result.push_str(format_unsafety(unsafety));
+    result.push_str(format_safety(safety));
 
     let shape = if context.config.version() == Version::Two {
         Shape::indented(offset + last_line_width(&result), context.config)
@@ -1137,7 +1137,7 @@
     };
     let ast::Trait {
         is_auto,
-        unsafety,
+        safety,
         ref generics,
         ref bounds,
         ref items,
@@ -1147,7 +1147,7 @@
     let header = format!(
         "{}{}{}trait ",
         format_visibility(context, &item.vis),
-        format_unsafety(unsafety),
+        format_safety(safety),
         format_auto(is_auto),
     );
     result.push_str(&header);
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index fe2d28a..75dea90 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -899,7 +899,7 @@
         result.push_str("> ");
     }
 
-    result.push_str(crate::utils::format_unsafety(bare_fn.unsafety));
+    result.push_str(crate::utils::format_safety(bare_fn.safety));
 
     result.push_str(&format_extern(
         bare_fn.ext,
diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs
index b91d9b4..09e1dbd 100644
--- a/src/tools/rustfmt/src/utils.rs
+++ b/src/tools/rustfmt/src/utils.rs
@@ -108,10 +108,10 @@
 }
 
 #[inline]
-pub(crate) fn format_unsafety(unsafety: ast::Unsafe) -> &'static str {
+pub(crate) fn format_safety(unsafety: ast::Safety) -> &'static str {
     match unsafety {
-        ast::Unsafe::Yes(..) => "unsafe ",
-        ast::Unsafe::No => "",
+        ast::Safety::Unsafe(..) => "unsafe ",
+        ast::Safety::Default => "",
     }
 }
 
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index 6209b37..7a0c68c 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -24,7 +24,7 @@
 use crate::spanned::Spanned;
 use crate::stmt::Stmt;
 use crate::utils::{
-    self, contains_skip, count_newlines, depr_skip_annotation, format_unsafety, inner_attributes,
+    self, contains_skip, count_newlines, depr_skip_annotation, format_safety, inner_attributes,
     last_line_width, mk_sp, ptr_vec_to_ref_vec, rewrite_ident, starts_with_newline, stmt_expr,
 };
 use crate::{ErrorKind, FormatReport, FormattingError};
@@ -517,9 +517,9 @@
                     self.visit_enum(item.ident, &item.vis, def, generics, item.span);
                     self.last_pos = source!(self, item.span).hi();
                 }
-                ast::ItemKind::Mod(unsafety, ref mod_kind) => {
+                ast::ItemKind::Mod(safety, ref mod_kind) => {
                     self.format_missing_with_indent(source!(self, item.span).lo());
-                    self.format_mod(mod_kind, unsafety, &item.vis, item.span, item.ident, attrs);
+                    self.format_mod(mod_kind, safety, &item.vis, item.span, item.ident, attrs);
                 }
                 ast::ItemKind::MacCall(ref mac) => {
                     self.visit_mac(mac, Some(item.ident), MacroPosition::Item);
@@ -586,7 +586,7 @@
                     );
                     self.push_rewrite(item.span, rewrite);
                 }
-                ast::ItemKind::Delegation(..) => {
+                ast::ItemKind::Delegation(..) | ast::ItemKind::DelegationMac(..) => {
                     // TODO: rewrite delegation items once syntax is established.
                     // For now, leave the contents of the Span unformatted.
                     self.push_rewrite(item.span, None)
@@ -913,7 +913,7 @@
     fn format_mod(
         &mut self,
         mod_kind: &ast::ModKind,
-        unsafety: ast::Unsafe,
+        safety: ast::Safety,
         vis: &ast::Visibility,
         s: Span,
         ident: symbol::Ident,
@@ -921,7 +921,7 @@
     ) {
         let vis_str = utils::format_visibility(&self.get_context(), vis);
         self.push_str(&*vis_str);
-        self.push_str(format_unsafety(unsafety));
+        self.push_str(format_safety(safety));
         self.push_str("mod ");
         // Calling `to_owned()` to work around borrow checker.
         let ident_str = rewrite_ident(&self.get_context(), ident).to_owned();
diff --git a/src/tools/tidy/config/black.toml b/src/tools/tidy/config/black.toml
index 51a7229..e73847a 100644
--- a/src/tools/tidy/config/black.toml
+++ b/src/tools/tidy/config/black.toml
@@ -11,5 +11,6 @@
     src/doc/edition-guide/|\
     src/llvm-project/|\
     src/doc/embedded-book/|\
+    src/tools/rustc-perf/|\
     library/backtrace/
     )"""
diff --git a/src/tools/tidy/config/ruff.toml b/src/tools/tidy/config/ruff.toml
index cf08c62..cf89ffd9 100644
--- a/src/tools/tidy/config/ruff.toml
+++ b/src/tools/tidy/config/ruff.toml
@@ -26,6 +26,7 @@
     "src/llvm-project/",
     "src/doc/embedded-book/",
     "library/backtrace/",
+    "src/tools/rustc-perf/",
     # Hack: CI runs from a subdirectory under the main checkout
     "../src/doc/nomicon/",
     "../src/tools/cargo/",
@@ -38,4 +39,5 @@
     "../src/llvm-project/",
     "../src/doc/embedded-book/",
     "../library/backtrace/",
+    "../src/tools/rustc-perf/",
 ]
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index f4ae7b0..96fb8e2 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -1,6 +1,3 @@
-run-make/alloc-no-oom-handling/Makefile
-run-make/alloc-no-rc/Makefile
-run-make/alloc-no-sync/Makefile
 run-make/allocator-shim-circular-deps/Makefile
 run-make/allow-non-lint-warnings-cmdline/Makefile
 run-make/allow-warnings-cmdline-stability/Makefile
@@ -11,8 +8,6 @@
 run-make/c-dynamic-dylib/Makefile
 run-make/c-dynamic-rlib/Makefile
 run-make/c-link-to-rust-dylib/Makefile
-run-make/c-link-to-rust-staticlib/Makefile
-run-make/c-link-to-rust-va-list-fn/Makefile
 run-make/c-static-dylib/Makefile
 run-make/c-static-rlib/Makefile
 run-make/c-unwind-abi-catch-lib-panic/Makefile
@@ -98,8 +93,6 @@
 run-make/issue-107094/Makefile
 run-make/issue-10971-temps-dir/Makefile
 run-make/issue-109934-lto-debuginfo/Makefile
-run-make/issue-11908/Makefile
-run-make/issue-14500/Makefile
 run-make/issue-14698/Makefile
 run-make/issue-15460/Makefile
 run-make/issue-18943/Makefile
@@ -110,7 +103,6 @@
 run-make/issue-26006/Makefile
 run-make/issue-26092/Makefile
 run-make/issue-28595/Makefile
-run-make/issue-28766/Makefile
 run-make/issue-30063/Makefile
 run-make/issue-33329/Makefile
 run-make/issue-35164/Makefile
@@ -135,7 +127,6 @@
 run-make/issue-85441/Makefile
 run-make/issue-88756-default-output/Makefile
 run-make/issue-97463-abi-param-passing/Makefile
-run-make/issue64319/Makefile
 run-make/jobserver-error/Makefile
 run-make/libs-through-symlinks/Makefile
 run-make/libtest-json/Makefile
@@ -185,9 +176,7 @@
 run-make/no-alloc-shim/Makefile
 run-make/no-builtins-attribute/Makefile
 run-make/no-builtins-lto/Makefile
-run-make/no-cdylib-as-rdylib/Makefile
 run-make/no-duplicate-libs/Makefile
-run-make/no-intermediate-extras/Makefile
 run-make/obey-crate-type-flag/Makefile
 run-make/optimization-remarks-dir-pgo/Makefile
 run-make/optimization-remarks-dir/Makefile
@@ -198,7 +187,6 @@
 run-make/override-aliased-flags/Makefile
 run-make/overwrite-input/Makefile
 run-make/panic-abort-eh_frame/Makefile
-run-make/panic-impl-transitive/Makefile
 run-make/pass-linker-flags-flavor/Makefile
 run-make/pass-linker-flags-from-dep/Makefile
 run-make/pass-linker-flags/Makefile
@@ -245,20 +233,8 @@
 run-make/rmeta-preferred/Makefile
 run-make/rustc-macro-dep-files/Makefile
 run-make/rustdoc-io-error/Makefile
-run-make/rustdoc-map-file/Makefile
-run-make/rustdoc-output-path/Makefile
-run-make/rustdoc-scrape-examples-invalid-expr/Makefile
 run-make/rustdoc-scrape-examples-macros/Makefile
-run-make/rustdoc-scrape-examples-multiple/Makefile
-run-make/rustdoc-scrape-examples-ordering/Makefile
-run-make/rustdoc-scrape-examples-remap/Makefile
-run-make/rustdoc-scrape-examples-test/Makefile
-run-make/rustdoc-scrape-examples-whitespace/Makefile
-run-make/rustdoc-shared-flags/Makefile
-run-make/rustdoc-target-spec-json-path/Makefile
-run-make/rustdoc-themes/Makefile
 run-make/rustdoc-verify-output-files/Makefile
-run-make/rustdoc-with-out-dir-option/Makefile
 run-make/rustdoc-with-output-option/Makefile
 run-make/rustdoc-with-short-out-dir-option/Makefile
 run-make/sanitizer-cdylib-link/Makefile
@@ -280,7 +256,6 @@
 run-make/static-dylib-by-default/Makefile
 run-make/static-extern-type/Makefile
 run-make/static-pie/Makefile
-run-make/static-unwinding/Makefile
 run-make/staticlib-blank-lib/Makefile
 run-make/staticlib-dylib-linkage/Makefile
 run-make/std-core-cycle/Makefile
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 1d24c59..efcd2a1 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -81,12 +81,10 @@
     ("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc
     ("colored", "MPL-2.0"),                                  // rustfmt
     ("dissimilar", "Apache-2.0"),                            // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps)
-    ("encoding_rs", "(Apache-2.0 OR MIT) AND BSD-3-Clause"), // opt-dist
     ("fluent-langneg", "Apache-2.0"),                        // rustc (fluent translations)
     ("fortanix-sgx-abi", "MPL-2.0"),                         // libstd but only for `sgx` target. FIXME: this dependency violates the documentation comment above.
     ("instant", "BSD-3-Clause"),                             // rustc_driver/tracing-subscriber/parking_lot
     ("mdbook", "MPL-2.0"),                                   // mdbook
-    ("openssl", "Apache-2.0"),                               // opt-dist
     ("option-ext", "MPL-2.0"),                               // cargo-miri (via `directories`)
     ("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"),     // rustc (license is the same as LLVM uses)
     ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0                       // cargo/... (because of serde)
@@ -135,6 +133,7 @@
     // tidy-alphabetical-start
     ("dissimilar", "Apache-2.0"),
     ("notify", "CC0-1.0"),
+    ("option-ext", "MPL-2.0"),
     ("pulldown-cmark-to-cmark", "Apache-2.0"),
     ("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"),
     ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0
@@ -395,6 +394,7 @@
     "windows_aarch64_gnullvm",
     "windows_aarch64_msvc",
     "windows_i686_gnu",
+    "windows_i686_gnullvm",
     "windows_i686_msvc",
     "windows_x86_64_gnu",
     "windows_x86_64_gnullvm",
diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt
index a931782..6b8106b 100644
--- a/src/tools/tidy/src/issues.txt
+++ b/src/tools/tidy/src/issues.txt
@@ -2915,7 +2915,6 @@
 ui/macros/issue-95533.rs
 ui/macros/issue-98466-allow.rs
 ui/macros/issue-98466.rs
-ui/macros/issue-98790.rs
 ui/macros/issue-99261.rs
 ui/macros/issue-99265.rs
 ui/macros/issue-99907.rs
diff --git a/src/tools/tidy/src/iter_header.rs b/src/tools/tidy/src/iter_header.rs
index ae63590..684c789 100644
--- a/src/tools/tidy/src/iter_header.rs
+++ b/src/tools/tidy/src/iter_header.rs
@@ -3,6 +3,7 @@
 /// A header line, like `//@name: value` consists of the prefix `//@` and the directive
 /// `name: value`. It is also possibly revisioned, e.g. `//@[revision] name: value`.
 pub(crate) struct HeaderLine<'ln> {
+    pub(crate) line_number: usize,
     pub(crate) revision: Option<&'ln str>,
     pub(crate) directive: &'ln str,
 }
@@ -11,7 +12,7 @@
 ///
 /// Adjusted from compiletest/src/header.rs.
 pub(crate) fn iter_header<'ln>(contents: &'ln str, it: &mut dyn FnMut(HeaderLine<'ln>)) {
-    for ln in contents.lines() {
+    for (line_number, ln) in (1..).zip(contents.lines()) {
         let ln = ln.trim();
 
         // We're left with potentially `[rev]name: value`.
@@ -24,9 +25,9 @@
                 panic!("malformed revision directive: expected `//@[rev]`, found `{ln}`");
             };
             // We trimmed off the `[rev]` portion, left with `name: value`.
-            it(HeaderLine { revision: Some(revision), directive: remainder.trim() });
+            it(HeaderLine { line_number, revision: Some(revision), directive: remainder.trim() });
         } else {
-            it(HeaderLine { revision: None, directive: remainder.trim() });
+            it(HeaderLine { line_number, revision: None, directive: remainder.trim() });
         }
     }
 }
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index c15081a..ae9d2b8 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -87,6 +87,7 @@
 pub mod tests_revision_unpaired_stdout_stderr;
 pub mod ui_tests;
 pub mod unit_tests;
+pub mod unknown_revision;
 pub mod unstable_book;
 pub mod walk;
 pub mod x_version;
diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs
index 7769181..1d2b2e4 100644
--- a/src/tools/tidy/src/main.rs
+++ b/src/tools/tidy/src/main.rs
@@ -110,6 +110,7 @@
         check!(rustdoc_gui_tests, &tests_path);
         check!(rustdoc_css_themes, &librustdoc_path);
         check!(known_bug, &crashes_path);
+        check!(unknown_revision, &tests_path);
 
         // Checks that only make sense for the compiler.
         check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose);
diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs
index cb242bf..c876aae 100644
--- a/src/tools/tidy/src/target_specific_tests.rs
+++ b/src/tools/tidy/src/target_specific_tests.rs
@@ -20,7 +20,7 @@
     crate::walk::walk(path, |path, _is_dir| filter_not_rust(path), &mut |entry, content| {
         let file = entry.path().display();
         let mut header_map = BTreeMap::new();
-        iter_header(content, &mut |HeaderLine { revision, directive }| {
+        iter_header(content, &mut |HeaderLine { revision, directive, .. }| {
             if let Some(value) = directive.strip_prefix(LLVM_COMPONENTS_HEADER) {
                 let info = header_map.entry(revision).or_insert(RevisionInfo::default());
                 let comp_vec = info.llvm_components.get_or_insert(Vec::new());
diff --git a/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs b/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs
index a0773c8..00edf99 100644
--- a/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs
+++ b/src/tools/tidy/src/tests_revision_unpaired_stdout_stderr.rs
@@ -61,7 +61,7 @@
             let contents = std::fs::read_to_string(test).unwrap();
 
             // Collect directives.
-            iter_header(&contents, &mut |HeaderLine { revision, directive }| {
+            iter_header(&contents, &mut |HeaderLine { revision, directive, .. }| {
                 // We're trying to *find* `//@ revision: xxx` directives themselves, not revisioned
                 // directives.
                 if revision.is_some() {
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 94a0eee..e1c6c9a 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -16,7 +16,7 @@
 // FIXME: The following limits should be reduced eventually.
 
 const ISSUES_ENTRY_LIMIT: usize = 1676;
-const ROOT_ENTRY_LIMIT: usize = 859;
+const ROOT_ENTRY_LIMIT: usize = 757;
 
 const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
     "rs",     // test source files
@@ -41,6 +41,7 @@
     "tests/ui/macros/not-utf8.bin", // testing including data with the include macros
     "tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include
     "tests/ui/proc-macro/auxiliary/included-file.txt", // more include
+    "tests/ui/unpretty/auxiliary/data.txt", // more include
     "tests/ui/invalid/foo.natvis.xml", // sample debugger visualizer
     "tests/ui/sanitizer/dataflow-abilist.txt", // dataflow sanitizer ABI list file
     "tests/ui/shell-argfiles/shell-argfiles.args", // passing args via a file
diff --git a/src/tools/tidy/src/unknown_revision.rs b/src/tools/tidy/src/unknown_revision.rs
new file mode 100644
index 0000000..abfff1d
--- /dev/null
+++ b/src/tools/tidy/src/unknown_revision.rs
@@ -0,0 +1,114 @@
+//! Checks that test revision names appearing in header directives and error
+//! annotations have actually been declared in `revisions`.
+
+// FIXME(jieyouxu) Ideally these checks would be integrated into compiletest's
+// own directive and revision handling, but for now they've been split out as a
+// separate `tidy` check to avoid making compiletest even messier.
+
+use std::collections::{BTreeSet, HashMap, HashSet};
+use std::path::Path;
+use std::sync::OnceLock;
+
+use ignore::DirEntry;
+use regex::Regex;
+
+use crate::iter_header::{iter_header, HeaderLine};
+use crate::walk::{filter_dirs, filter_not_rust, walk};
+
+pub fn check(tests_path: impl AsRef<Path>, bad: &mut bool) {
+    walk(
+        tests_path.as_ref(),
+        |path, is_dir| {
+            filter_dirs(path) || filter_not_rust(path) || {
+                // Auxiliary source files for incremental tests can refer to revisions
+                // declared by the main file, which this check doesn't handle.
+                is_dir && path.file_name().is_some_and(|name| name == "auxiliary")
+            }
+        },
+        &mut |entry, contents| visit_test_file(entry, contents, bad),
+    );
+}
+
+fn visit_test_file(entry: &DirEntry, contents: &str, bad: &mut bool) {
+    let mut revisions = HashSet::new();
+    let mut unused_revision_names = HashSet::new();
+
+    // Maps each mentioned revision to the first line it was mentioned on.
+    let mut mentioned_revisions = HashMap::<&str, usize>::new();
+    let mut add_mentioned_revision = |line_number: usize, revision| {
+        let first_line = mentioned_revisions.entry(revision).or_insert(line_number);
+        *first_line = (*first_line).min(line_number);
+    };
+
+    // Scan all `//@` headers to find declared revisions and mentioned revisions.
+    iter_header(contents, &mut |HeaderLine { line_number, revision, directive }| {
+        if let Some(revs) = directive.strip_prefix("revisions:") {
+            revisions.extend(revs.split_whitespace());
+        } else if let Some(revs) = directive.strip_prefix("unused-revision-names:") {
+            unused_revision_names.extend(revs.split_whitespace());
+        }
+
+        if let Some(revision) = revision {
+            add_mentioned_revision(line_number, revision);
+        }
+    });
+
+    // If a wildcard appears in `unused-revision-names`, skip all revision name
+    // checking for this file.
+    if unused_revision_names.contains(&"*") {
+        return;
+    }
+
+    // Scan all `//[rev]~` error annotations to find mentioned revisions.
+    for_each_error_annotation_revision(contents, &mut |ErrorAnnRev { line_number, revision }| {
+        add_mentioned_revision(line_number, revision);
+    });
+
+    let path = entry.path().display();
+
+    // Fail if any revision names appear in both places, since that's probably a mistake.
+    for rev in revisions.intersection(&unused_revision_names).copied().collect::<BTreeSet<_>>() {
+        tidy_error!(
+            bad,
+            "revision name [{rev}] appears in both `revisions` and `unused-revision-names` in {path}"
+        );
+    }
+
+    // Compute the set of revisions that were mentioned but not declared,
+    // sorted by the first line number they appear on.
+    let mut bad_revisions = mentioned_revisions
+        .into_iter()
+        .filter(|(rev, _)| !revisions.contains(rev) && !unused_revision_names.contains(rev))
+        .map(|(rev, line_number)| (line_number, rev))
+        .collect::<Vec<_>>();
+    bad_revisions.sort();
+
+    for (line_number, rev) in bad_revisions {
+        tidy_error!(bad, "unknown revision [{rev}] at {path}:{line_number}");
+    }
+}
+
+struct ErrorAnnRev<'a> {
+    line_number: usize,
+    revision: &'a str,
+}
+
+fn for_each_error_annotation_revision<'a>(
+    contents: &'a str,
+    callback: &mut dyn FnMut(ErrorAnnRev<'a>),
+) {
+    let error_regex = {
+        // Simplified from the regex used by `parse_expected` in `src/tools/compiletest/src/errors.rs`,
+        // because we only care about extracting revision names.
+        static RE: OnceLock<Regex> = OnceLock::new();
+        RE.get_or_init(|| Regex::new(r"//\[(?<revs>[^]]*)\]~").unwrap())
+    };
+
+    for (line_number, line) in (1..).zip(contents.lines()) {
+        let Some(captures) = error_regex.captures(line) else { continue };
+
+        for revision in captures.name("revs").unwrap().as_str().split(',') {
+            callback(ErrorAnnRev { line_number, revision });
+        }
+    }
+}
diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs
index 851c21f..f68b767 100644
--- a/src/tools/tidy/src/walk.rs
+++ b/src/tools/tidy/src/walk.rs
@@ -18,6 +18,7 @@
         "src/tools/clippy",
         "src/tools/miri",
         "src/tools/rust-analyzer",
+        "src/tools/rustc-perf",
         "src/tools/rustfmt",
         "src/doc/book",
         "src/doc/edition-guide",
diff --git a/tests/assembly/targets/targets-elf.rs b/tests/assembly/targets/targets-elf.rs
index 3563aec..0db2a35 100644
--- a/tests/assembly/targets/targets-elf.rs
+++ b/tests/assembly/targets/targets-elf.rs
@@ -555,6 +555,9 @@
 //@ revisions: x86_64_unknown_linux_ohos
 //@ [x86_64_unknown_linux_ohos] compile-flags: --target x86_64-unknown-linux-ohos
 //@ [x86_64_unknown_linux_ohos] needs-llvm-components: x86
+//@ revisions: x86_64_unknown_linux_none
+//@ [x86_64_unknown_linux_none] compile-flags: --target x86_64-unknown-linux-none
+//@ [x86_64_unknown_linux_none] needs-llvm-components: x86
 //@ revisions: x86_64_unknown_netbsd
 //@ [x86_64_unknown_netbsd] compile-flags: --target x86_64-unknown-netbsd
 //@ [x86_64_unknown_netbsd] needs-llvm-components: x86
diff --git a/tests/auxiliary/rust_test_helpers.c b/tests/auxiliary/rust_test_helpers.c
index 965df44..34cc7fd 100644
--- a/tests/auxiliary/rust_test_helpers.c
+++ b/tests/auxiliary/rust_test_helpers.c
@@ -27,10 +27,10 @@
     return u;
 }
 
-typedef void *(*dbg_callback)(void*);
+typedef uint64_t (*dbg_callback)(uint64_t);
 
-void *
-rust_dbg_call(dbg_callback cb, void *data) {
+uint64_t
+rust_dbg_call(dbg_callback cb, uint64_t data) {
     return cb(data);
 }
 
diff --git a/tests/codegen-units/partitioning/extern-drop-glue.rs b/tests/codegen-units/partitioning/extern-drop-glue.rs
index 84eb802..d3bce7b 100644
--- a/tests/codegen-units/partitioning/extern-drop-glue.rs
+++ b/tests/codegen-units/partitioning/extern-drop-glue.rs
@@ -1,7 +1,4 @@
-//
-
-// We specify incremental here because we want to test the partitioning for
-//@ incremental compilation
+// We specify incremental here because we want to test the partitioning for incremental compilation
 // We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=lazy
diff --git a/tests/codegen-units/partitioning/extern-generic.rs b/tests/codegen-units/partitioning/extern-generic.rs
index abd3918..0e4b6a3 100644
--- a/tests/codegen-units/partitioning/extern-generic.rs
+++ b/tests/codegen-units/partitioning/extern-generic.rs
@@ -1,6 +1,4 @@
-//
-// We specify incremental here because we want to test the partitioning for
-//@ incremental compilation
+// We specify incremental here because we want to test the partitioning for incremental compilation
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=eager -Zshare-generics=y
 
diff --git a/tests/codegen-units/partitioning/incremental-merging.rs b/tests/codegen-units/partitioning/incremental-merging.rs
index b44090c..6834bb2 100644
--- a/tests/codegen-units/partitioning/incremental-merging.rs
+++ b/tests/codegen-units/partitioning/incremental-merging.rs
@@ -1,5 +1,4 @@
-// We specify incremental here because we want to test the partitioning for
-//@ incremental compilation
+// We specify incremental here because we want to test the partitioning for incremental compilation
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=lazy
 //@ compile-flags:-Ccodegen-units=3
diff --git a/tests/codegen-units/partitioning/inlining-from-extern-crate.rs b/tests/codegen-units/partitioning/inlining-from-extern-crate.rs
index 74734d3..d021f46 100644
--- a/tests/codegen-units/partitioning/inlining-from-extern-crate.rs
+++ b/tests/codegen-units/partitioning/inlining-from-extern-crate.rs
@@ -1,6 +1,4 @@
-//
-// We specify incremental here because we want to test the partitioning for
-//@ incremental compilation
+// We specify incremental here because we want to test the partitioning for incremental compilation
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=lazy
 //@ compile-flags:-Zinline-in-all-cgus
diff --git a/tests/codegen-units/partitioning/local-drop-glue.rs b/tests/codegen-units/partitioning/local-drop-glue.rs
index 0974187..5fa1df9 100644
--- a/tests/codegen-units/partitioning/local-drop-glue.rs
+++ b/tests/codegen-units/partitioning/local-drop-glue.rs
@@ -1,6 +1,4 @@
-//
-// We specify incremental here because we want to test the partitioning for
-//@ incremental compilation
+// We specify incremental here because we want to test the partitioning for incremental compilation
 // We specify opt-level=0 because `drop_in_place` is `Internal` when optimizing
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=lazy
diff --git a/tests/codegen-units/partitioning/local-generic.rs b/tests/codegen-units/partitioning/local-generic.rs
index 2cfdc27..06f46b2 100644
--- a/tests/codegen-units/partitioning/local-generic.rs
+++ b/tests/codegen-units/partitioning/local-generic.rs
@@ -1,5 +1,4 @@
-// We specify incremental here because we want to test the partitioning for
-//@ incremental compilation
+// We specify incremental here because we want to test the partitioning for incremental compilation
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=eager
 
diff --git a/tests/codegen-units/partitioning/local-inlining-but-not-all.rs b/tests/codegen-units/partitioning/local-inlining-but-not-all.rs
index 49a2ce7..2f9cbe8 100644
--- a/tests/codegen-units/partitioning/local-inlining-but-not-all.rs
+++ b/tests/codegen-units/partitioning/local-inlining-but-not-all.rs
@@ -1,6 +1,4 @@
-//
-// We specify incremental here because we want to test the partitioning for
-//@ incremental compilation
+// We specify incremental here because we want to test the partitioning for incremental compilation
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=lazy
 //@ compile-flags:-Zinline-in-all-cgus=no
diff --git a/tests/codegen-units/partitioning/local-inlining.rs b/tests/codegen-units/partitioning/local-inlining.rs
index 726cf2b..2329a87 100644
--- a/tests/codegen-units/partitioning/local-inlining.rs
+++ b/tests/codegen-units/partitioning/local-inlining.rs
@@ -1,6 +1,4 @@
-//
-// We specify incremental here because we want to test the partitioning for
-//@ incremental compilation
+// We specify incremental here because we want to test the partitioning for incremental compilation
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=lazy
 //@ compile-flags:-Zinline-in-all-cgus
diff --git a/tests/codegen-units/partitioning/local-transitive-inlining.rs b/tests/codegen-units/partitioning/local-transitive-inlining.rs
index 355eb6c..4ccc53a 100644
--- a/tests/codegen-units/partitioning/local-transitive-inlining.rs
+++ b/tests/codegen-units/partitioning/local-transitive-inlining.rs
@@ -1,6 +1,4 @@
-//
-// We specify incremental here because we want to test the partitioning for
-//@ incremental compilation
+// We specify incremental here because we want to test the partitioning for incremental compilation
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=lazy
 //@ compile-flags:-Zinline-in-all-cgus
diff --git a/tests/codegen-units/partitioning/methods-are-with-self-type.rs b/tests/codegen-units/partitioning/methods-are-with-self-type.rs
index 2e54725..3ba5333 100644
--- a/tests/codegen-units/partitioning/methods-are-with-self-type.rs
+++ b/tests/codegen-units/partitioning/methods-are-with-self-type.rs
@@ -3,9 +3,7 @@
 // much sense at the moment.
 //@ ignore-test
 
-//
-// We specify incremental here because we want to test the partitioning for
-//@ incremental compilation
+// We specify incremental here because we want to test the partitioning for incremental compilation
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=lazy
 
diff --git a/tests/codegen-units/partitioning/regular-modules.rs b/tests/codegen-units/partitioning/regular-modules.rs
index 0eb0848..6860197 100644
--- a/tests/codegen-units/partitioning/regular-modules.rs
+++ b/tests/codegen-units/partitioning/regular-modules.rs
@@ -1,5 +1,4 @@
-// We specify incremental here because we want to test the partitioning for
-//@ incremental compilation
+// We specify incremental here because we want to test the partitioning for incremental compilation
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=eager
 
diff --git a/tests/codegen-units/partitioning/shared-generics.rs b/tests/codegen-units/partitioning/shared-generics.rs
index 25ea7fa..5b78794 100644
--- a/tests/codegen-units/partitioning/shared-generics.rs
+++ b/tests/codegen-units/partitioning/shared-generics.rs
@@ -1,4 +1,3 @@
-//
 //@ no-prefer-dynamic
 // NOTE: We always compile this test with -Copt-level=0 because higher opt-levels
 //       prevent drop-glue from participating in share-generics.
diff --git a/tests/codegen-units/partitioning/statics.rs b/tests/codegen-units/partitioning/statics.rs
index 9503a91..c7eef1f 100644
--- a/tests/codegen-units/partitioning/statics.rs
+++ b/tests/codegen-units/partitioning/statics.rs
@@ -1,5 +1,4 @@
-// We specify incremental here because we want to test the partitioning for
-//@ incremental compilation
+// We specify incremental here because we want to test the partitioning for incremental compilation
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=lazy
 
diff --git a/tests/codegen-units/partitioning/vtable-through-const.rs b/tests/codegen-units/partitioning/vtable-through-const.rs
index 111b4fa..ca4d382 100644
--- a/tests/codegen-units/partitioning/vtable-through-const.rs
+++ b/tests/codegen-units/partitioning/vtable-through-const.rs
@@ -1,7 +1,4 @@
-//
-
-// We specify incremental here because we want to test the partitioning for
-//@ incremental compilation
+// We specify incremental here because we want to test the partitioning for incremental compilation
 //@ incremental
 //@ compile-flags:-Zprint-mono-items=lazy
 //@ compile-flags:-Zinline-in-all-cgus
diff --git a/tests/codegen/array-cmp.rs b/tests/codegen/array-cmp.rs
new file mode 100644
index 0000000..194c0ad
--- /dev/null
+++ b/tests/codegen/array-cmp.rs
@@ -0,0 +1,18 @@
+// Ensure the asm for array comparisons is properly optimized.
+
+//@ compile-flags: -C opt-level=2
+
+#![crate_type = "lib"]
+
+// CHECK-LABEL: @compare
+// CHECK: start:
+// CHECK-NEXT: ret i1 true
+#[no_mangle]
+pub fn compare() -> bool {
+    let bytes = 12.5f32.to_ne_bytes();
+    bytes == if cfg!(target_endian = "big") {
+        [0x41, 0x48, 0x00, 0x00]
+    } else {
+        [0x00, 0x00, 0x48, 0x41]
+    }
+}
diff --git a/tests/codegen/float/f128.rs b/tests/codegen/float/f128.rs
index 97d545e..32c5be1 100644
--- a/tests/codegen/float/f128.rs
+++ b/tests/codegen/float/f128.rs
@@ -2,6 +2,7 @@
 
 #![crate_type = "lib"]
 #![feature(f128)]
+#![feature(f16)]
 #![feature(core_intrinsics)]
 
 // CHECK-LABEL: i1 @f128_eq(
@@ -127,3 +128,196 @@
     // CHECK-NEXT: store fp128 %{{.+}}, ptr %{{.+}}
     *a %= b
 }
+
+/* float to float conversions */
+
+// CHECK-LABEL: half @f128_as_f16(
+#[no_mangle]
+pub fn f128_as_f16(a: f128) -> f16 {
+    // CHECK: fptrunc fp128 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: float @f128_as_f32(
+#[no_mangle]
+pub fn f128_as_f32(a: f128) -> f32 {
+    // CHECK: fptrunc fp128 %{{.+}} to float
+    a as f32
+}
+
+// CHECK-LABEL: double @f128_as_f64(
+#[no_mangle]
+pub fn f128_as_f64(a: f128) -> f64 {
+    // CHECK: fptrunc fp128 %{{.+}} to double
+    a as f64
+}
+
+// CHECK-LABEL: fp128 @f128_as_self(
+#[no_mangle]
+pub fn f128_as_self(a: f128) -> f128 {
+    // CHECK: ret fp128 %{{.+}}
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @f16_as_f128(
+#[no_mangle]
+pub fn f16_as_f128(a: f16) -> f128 {
+    // CHECK: fpext half %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @f32_as_f128(
+#[no_mangle]
+pub fn f32_as_f128(a: f32) -> f128 {
+    // CHECK: fpext float %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @f64_as_f128(
+#[no_mangle]
+pub fn f64_as_f128(a: f64) -> f128 {
+    // CHECK: fpext double %{{.+}} to fp128
+    a as f128
+}
+
+/* float to int conversions */
+
+// CHECK-LABEL: i8 @f128_as_u8(
+#[no_mangle]
+pub fn f128_as_u8(a: f128) -> u8 {
+    // CHECK: call i8 @llvm.fptoui.sat.i8.f128(fp128 %{{.+}})
+    a as u8
+}
+
+#[no_mangle]
+pub fn f128_as_u16(a: f128) -> u16 {
+    // CHECK: call i16 @llvm.fptoui.sat.i16.f128(fp128 %{{.+}})
+    a as u16
+}
+
+// CHECK-LABEL: i32 @f128_as_u32(
+#[no_mangle]
+pub fn f128_as_u32(a: f128) -> u32 {
+    // CHECK: call i32 @llvm.fptoui.sat.i32.f128(fp128 %{{.+}})
+    a as u32
+}
+
+// CHECK-LABEL: i64 @f128_as_u64(
+#[no_mangle]
+pub fn f128_as_u64(a: f128) -> u64 {
+    // CHECK: call i64 @llvm.fptoui.sat.i64.f128(fp128 %{{.+}})
+    a as u64
+}
+
+// CHECK-LABEL: i128 @f128_as_u128(
+#[no_mangle]
+pub fn f128_as_u128(a: f128) -> u128 {
+    // CHECK: call i128 @llvm.fptoui.sat.i128.f128(fp128 %{{.+}})
+    a as u128
+}
+
+// CHECK-LABEL: i8 @f128_as_i8(
+#[no_mangle]
+pub fn f128_as_i8(a: f128) -> i8 {
+    // CHECK: call i8 @llvm.fptosi.sat.i8.f128(fp128 %{{.+}})
+    a as i8
+}
+
+// CHECK-LABEL: i16 @f128_as_i16(
+#[no_mangle]
+pub fn f128_as_i16(a: f128) -> i16 {
+    // CHECK: call i16 @llvm.fptosi.sat.i16.f128(fp128 %{{.+}})
+    a as i16
+}
+// CHECK-LABEL: i32 @f128_as_i32(
+#[no_mangle]
+pub fn f128_as_i32(a: f128) -> i32 {
+    // CHECK: call i32 @llvm.fptosi.sat.i32.f128(fp128 %{{.+}})
+    a as i32
+}
+
+// CHECK-LABEL: i64 @f128_as_i64(
+#[no_mangle]
+pub fn f128_as_i64(a: f128) -> i64 {
+    // CHECK: call i64 @llvm.fptosi.sat.i64.f128(fp128 %{{.+}})
+    a as i64
+}
+
+// CHECK-LABEL: i128 @f128_as_i128(
+#[no_mangle]
+pub fn f128_as_i128(a: f128) -> i128 {
+    // CHECK: call i128 @llvm.fptosi.sat.i128.f128(fp128 %{{.+}})
+    a as i128
+}
+
+/* int to float conversions */
+
+// CHECK-LABEL: fp128 @u8_as_f128(
+#[no_mangle]
+pub fn u8_as_f128(a: u8) -> f128 {
+    // CHECK: uitofp i8 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @u16_as_f128(
+#[no_mangle]
+pub fn u16_as_f128(a: u16) -> f128 {
+    // CHECK: uitofp i16 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @u32_as_f128(
+#[no_mangle]
+pub fn u32_as_f128(a: u32) -> f128 {
+    // CHECK: uitofp i32 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @u64_as_f128(
+#[no_mangle]
+pub fn u64_as_f128(a: u64) -> f128 {
+    // CHECK: uitofp i64 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @u128_as_f128(
+#[no_mangle]
+pub fn u128_as_f128(a: u128) -> f128 {
+    // CHECK: uitofp i128 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i8_as_f128(
+#[no_mangle]
+pub fn i8_as_f128(a: i8) -> f128 {
+    // CHECK: sitofp i8 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i16_as_f128(
+#[no_mangle]
+pub fn i16_as_f128(a: i16) -> f128 {
+    // CHECK: sitofp i16 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i32_as_f128(
+#[no_mangle]
+pub fn i32_as_f128(a: i32) -> f128 {
+    // CHECK: sitofp i32 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i64_as_f128(
+#[no_mangle]
+pub fn i64_as_f128(a: i64) -> f128 {
+    // CHECK: sitofp i64 %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: fp128 @i128_as_f128(
+#[no_mangle]
+pub fn i128_as_f128(a: i128) -> f128 {
+    // CHECK: sitofp i128 %{{.+}} to fp128
+    a as f128
+}
diff --git a/tests/codegen/float/f16.rs b/tests/codegen/float/f16.rs
index d1f75cc..96daac8 100644
--- a/tests/codegen/float/f16.rs
+++ b/tests/codegen/float/f16.rs
@@ -1,9 +1,12 @@
 // Verify that our intrinsics generate the correct LLVM calls for f16
 
 #![crate_type = "lib"]
+#![feature(f128)]
 #![feature(f16)]
 #![feature(core_intrinsics)]
 
+/* arithmetic */
+
 // CHECK-LABEL: i1 @f16_eq(
 #[no_mangle]
 pub fn f16_eq(a: f16, b: f16) -> bool {
@@ -109,7 +112,7 @@
 pub fn f16_mul_assign(a: &mut f16, b: f16) {
     // CHECK: fmul half %{{.+}}, %{{.+}}
     // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
-    *a *= b
+    *a *= b;
 }
 
 // CHECK-LABEL: void @f16_div_assign(
@@ -117,7 +120,7 @@
 pub fn f16_div_assign(a: &mut f16, b: f16) {
     // CHECK: fdiv half %{{.+}}, %{{.+}}
     // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
-    *a /= b
+    *a /= b;
 }
 
 // CHECK-LABEL: void @f16_rem_assign(
@@ -125,5 +128,198 @@
 pub fn f16_rem_assign(a: &mut f16, b: f16) {
     // CHECK: frem half %{{.+}}, %{{.+}}
     // CHECK-NEXT: store half %{{.+}}, ptr %{{.+}}
-    *a %= b
+    *a %= b;
+}
+
+/* float to float conversions */
+
+// CHECK-LABEL: half @f16_as_self(
+#[no_mangle]
+pub fn f16_as_self(a: f16) -> f16 {
+    // CHECK: ret half %{{.+}}
+    a as f16
+}
+
+// CHECK-LABEL: float @f16_as_f32(
+#[no_mangle]
+pub fn f16_as_f32(a: f16) -> f32 {
+    // CHECK: fpext half %{{.+}} to float
+    a as f32
+}
+
+// CHECK-LABEL: double @f16_as_f64(
+#[no_mangle]
+pub fn f16_as_f64(a: f16) -> f64 {
+    // CHECK: fpext half %{{.+}} to double
+    a as f64
+}
+
+// CHECK-LABEL: fp128 @f16_as_f128(
+#[no_mangle]
+pub fn f16_as_f128(a: f16) -> f128 {
+    // CHECK: fpext half %{{.+}} to fp128
+    a as f128
+}
+
+// CHECK-LABEL: half @f32_as_f16(
+#[no_mangle]
+pub fn f32_as_f16(a: f32) -> f16 {
+    // CHECK: fptrunc float %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @f64_as_f16(
+#[no_mangle]
+pub fn f64_as_f16(a: f64) -> f16 {
+    // CHECK: fptrunc double %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @f128_as_f16(
+#[no_mangle]
+pub fn f128_as_f16(a: f128) -> f16 {
+    // CHECK: fptrunc fp128 %{{.+}} to half
+    a as f16
+}
+
+/* float to int conversions */
+
+// CHECK-LABEL: i8 @f16_as_u8(
+#[no_mangle]
+pub fn f16_as_u8(a: f16) -> u8 {
+    // CHECK: call i8 @llvm.fptoui.sat.i8.f16(half %{{.+}})
+    a as u8
+}
+
+#[no_mangle]
+pub fn f16_as_u16(a: f16) -> u16 {
+    // CHECK: call i16 @llvm.fptoui.sat.i16.f16(half %{{.+}})
+    a as u16
+}
+
+// CHECK-LABEL: i32 @f16_as_u32(
+#[no_mangle]
+pub fn f16_as_u32(a: f16) -> u32 {
+    // CHECK: call i32 @llvm.fptoui.sat.i32.f16(half %{{.+}})
+    a as u32
+}
+
+// CHECK-LABEL: i64 @f16_as_u64(
+#[no_mangle]
+pub fn f16_as_u64(a: f16) -> u64 {
+    // CHECK: call i64 @llvm.fptoui.sat.i64.f16(half %{{.+}})
+    a as u64
+}
+
+// CHECK-LABEL: i128 @f16_as_u128(
+#[no_mangle]
+pub fn f16_as_u128(a: f16) -> u128 {
+    // CHECK: call i128 @llvm.fptoui.sat.i128.f16(half %{{.+}})
+    a as u128
+}
+
+// CHECK-LABEL: i8 @f16_as_i8(
+#[no_mangle]
+pub fn f16_as_i8(a: f16) -> i8 {
+    // CHECK: call i8 @llvm.fptosi.sat.i8.f16(half %{{.+}})
+    a as i8
+}
+
+// CHECK-LABEL: i16 @f16_as_i16(
+#[no_mangle]
+pub fn f16_as_i16(a: f16) -> i16 {
+    // CHECK: call i16 @llvm.fptosi.sat.i16.f16(half %{{.+}})
+    a as i16
+}
+// CHECK-LABEL: i32 @f16_as_i32(
+#[no_mangle]
+pub fn f16_as_i32(a: f16) -> i32 {
+    // CHECK: call i32 @llvm.fptosi.sat.i32.f16(half %{{.+}})
+    a as i32
+}
+
+// CHECK-LABEL: i64 @f16_as_i64(
+#[no_mangle]
+pub fn f16_as_i64(a: f16) -> i64 {
+    // CHECK: call i64 @llvm.fptosi.sat.i64.f16(half %{{.+}})
+    a as i64
+}
+
+// CHECK-LABEL: i128 @f16_as_i128(
+#[no_mangle]
+pub fn f16_as_i128(a: f16) -> i128 {
+    // CHECK: call i128 @llvm.fptosi.sat.i128.f16(half %{{.+}})
+    a as i128
+}
+
+/* int to float conversions */
+
+// CHECK-LABEL: half @u8_as_f16(
+#[no_mangle]
+pub fn u8_as_f16(a: u8) -> f16 {
+    // CHECK: uitofp i8 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @u16_as_f16(
+#[no_mangle]
+pub fn u16_as_f16(a: u16) -> f16 {
+    // CHECK: uitofp i16 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @u32_as_f16(
+#[no_mangle]
+pub fn u32_as_f16(a: u32) -> f16 {
+    // CHECK: uitofp i32 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @u64_as_f16(
+#[no_mangle]
+pub fn u64_as_f16(a: u64) -> f16 {
+    // CHECK: uitofp i64 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @u128_as_f16(
+#[no_mangle]
+pub fn u128_as_f16(a: u128) -> f16 {
+    // CHECK: uitofp i128 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i8_as_f16(
+#[no_mangle]
+pub fn i8_as_f16(a: i8) -> f16 {
+    // CHECK: sitofp i8 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i16_as_f16(
+#[no_mangle]
+pub fn i16_as_f16(a: i16) -> f16 {
+    // CHECK: sitofp i16 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i32_as_f16(
+#[no_mangle]
+pub fn i32_as_f16(a: i32) -> f16 {
+    // CHECK: sitofp i32 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i64_as_f16(
+#[no_mangle]
+pub fn i64_as_f16(a: i64) -> f16 {
+    // CHECK: sitofp i64 %{{.+}} to half
+    a as f16
+}
+
+// CHECK-LABEL: half @i128_as_f16(
+#[no_mangle]
+pub fn i128_as_f16(a: i128) -> f16 {
+    // CHECK: sitofp i128 %{{.+}} to half
+    a as f16
 }
diff --git a/tests/codegen/intrinsics/aggregate-thin-pointer.rs b/tests/codegen/intrinsics/aggregate-thin-pointer.rs
new file mode 100644
index 0000000..aa3bf7e
--- /dev/null
+++ b/tests/codegen/intrinsics/aggregate-thin-pointer.rs
@@ -0,0 +1,23 @@
+//@ compile-flags: -O -C no-prepopulate-passes -Z mir-enable-passes=-InstSimplify
+//@ only-64bit (so I don't need to worry about usize)
+
+#![crate_type = "lib"]
+#![feature(core_intrinsics)]
+
+use std::intrinsics::aggregate_raw_ptr;
+
+// InstSimplify replaces these with casts if it can, which means they're almost
+// never seen in codegen, but PR#121571 found a way, so add a test for it.
+
+#[inline(never)]
+pub fn opaque(_p: &*const i32) {}
+
+// CHECK-LABEL: @thin_ptr_via_aggregate(
+#[no_mangle]
+pub unsafe fn thin_ptr_via_aggregate(p: *const ()) {
+    // CHECK: %mem = alloca
+    // CHECK: store ptr %p, ptr %mem
+    // CHECK: call {{.+}}aggregate_thin_pointer{{.+}} %mem)
+    let mem = aggregate_raw_ptr(p, ());
+    opaque(&mem);
+}
diff --git a/tests/codegen/mir-aggregate-no-alloca.rs b/tests/codegen/mir-aggregate-no-alloca.rs
new file mode 100644
index 0000000..c0e7e1a
--- /dev/null
+++ b/tests/codegen/mir-aggregate-no-alloca.rs
@@ -0,0 +1,123 @@
+//@ compile-flags: -O -C no-prepopulate-passes -Z randomize-layout=no
+
+#![crate_type = "lib"]
+
+#[repr(transparent)]
+pub struct Transparent32(u32);
+
+// CHECK: i32 @make_transparent(i32 noundef %x)
+#[no_mangle]
+pub fn make_transparent(x: u32) -> Transparent32 {
+    // CHECK-NOT: alloca
+    // CHECK: ret i32 %x
+    let a = Transparent32(x);
+    a
+}
+
+// CHECK: i32 @make_closure(i32 noundef %x)
+#[no_mangle]
+pub fn make_closure(x: i32) -> impl Fn(i32) -> i32 {
+    // CHECK-NOT: alloca
+    // CHECK: ret i32 %x
+    move |y| x + y
+}
+
+#[repr(transparent)]
+pub struct TransparentPair((), (u16, u16), ());
+
+// CHECK: { i16, i16 } @make_transparent_pair(i16 noundef %x.0, i16 noundef %x.1)
+#[no_mangle]
+pub fn make_transparent_pair(x: (u16, u16)) -> TransparentPair {
+    // CHECK-NOT: alloca
+    // CHECK: %[[TEMP0:.+]] = insertvalue { i16, i16 } poison, i16 %x.0, 0
+    // CHECK: %[[TEMP1:.+]] = insertvalue { i16, i16 } %[[TEMP0]], i16 %x.1, 1
+    // CHECK: ret { i16, i16 } %[[TEMP1]]
+    let a = TransparentPair((), x, ());
+    a
+}
+
+// CHECK-LABEL: { i32, i32 } @make_2_tuple(i32 noundef %x)
+#[no_mangle]
+pub fn make_2_tuple(x: u32) -> (u32, u32) {
+    // CHECK-NOT: alloca
+    // CHECK: %[[TEMP0:.+]] = insertvalue { i32, i32 } poison, i32 %x, 0
+    // CHECK: %[[TEMP1:.+]] = insertvalue { i32, i32 } %[[TEMP0]], i32 %x, 1
+    // CHECK: ret { i32, i32 } %[[TEMP1]]
+    let pair = (x, x);
+    pair
+}
+
+// CHECK-LABEL: i8 @make_cell_of_bool(i1 noundef zeroext %b)
+#[no_mangle]
+pub fn make_cell_of_bool(b: bool) -> std::cell::Cell<bool> {
+    // CHECK: %[[BYTE:.+]] = zext i1 %b to i8
+    // CHECK: ret i8 %[[BYTE]]
+    std::cell::Cell::new(b)
+}
+
+// CHECK-LABEL: { i8, i16 } @make_cell_of_bool_and_short(i1 noundef zeroext %b, i16 noundef %s)
+#[no_mangle]
+pub fn make_cell_of_bool_and_short(b: bool, s: u16) -> std::cell::Cell<(bool, u16)> {
+    // CHECK-NOT: alloca
+    // CHECK: %[[BYTE:.+]] = zext i1 %b to i8
+    // CHECK: %[[TEMP0:.+]] = insertvalue { i8, i16 } poison, i8 %[[BYTE]], 0
+    // CHECK: %[[TEMP1:.+]] = insertvalue { i8, i16 } %[[TEMP0]], i16 %s, 1
+    // CHECK: ret { i8, i16 } %[[TEMP1]]
+    std::cell::Cell::new((b, s))
+}
+
+// CHECK-LABEL: { i1, i1 } @make_tuple_of_bools(i1 noundef zeroext %a, i1 noundef zeroext %b)
+#[no_mangle]
+pub fn make_tuple_of_bools(a: bool, b: bool) -> (bool, bool) {
+    // CHECK-NOT: alloca
+    // CHECK: %[[TEMP0:.+]] = insertvalue { i1, i1 } poison, i1 %a, 0
+    // CHECK: %[[TEMP1:.+]] = insertvalue { i1, i1 } %[[TEMP0]], i1 %b, 1
+    // CHECK: ret { i1, i1 } %[[TEMP1]]
+    (a, b)
+}
+
+pub struct Struct0();
+
+// CHECK-LABEL: void @make_struct_0()
+#[no_mangle]
+pub fn make_struct_0() -> Struct0 {
+    // CHECK: ret void
+    let s = Struct0();
+    s
+}
+
+pub struct Struct1(i32);
+
+// CHECK-LABEL: i32 @make_struct_1(i32 noundef %a)
+#[no_mangle]
+pub fn make_struct_1(a: i32) -> Struct1 {
+    // CHECK: ret i32 %a
+    let s = Struct1(a);
+    s
+}
+
+pub struct Struct2Asc(i16, i64);
+
+// CHECK-LABEL: { i64, i16 } @make_struct_2_asc(i16 noundef %a, i64 noundef %b)
+#[no_mangle]
+pub fn make_struct_2_asc(a: i16, b: i64) -> Struct2Asc {
+    // CHECK-NOT: alloca
+    // CHECK: %[[TEMP0:.+]] = insertvalue { i64, i16 } poison, i64 %b, 0
+    // CHECK: %[[TEMP1:.+]] = insertvalue { i64, i16 } %[[TEMP0]], i16 %a, 1
+    // CHECK: ret { i64, i16 } %[[TEMP1]]
+    let s = Struct2Asc(a, b);
+    s
+}
+
+pub struct Struct2Desc(i64, i16);
+
+// CHECK-LABEL: { i64, i16 } @make_struct_2_desc(i64 noundef %a, i16 noundef %b)
+#[no_mangle]
+pub fn make_struct_2_desc(a: i64, b: i16) -> Struct2Desc {
+    // CHECK-NOT: alloca
+    // CHECK: %[[TEMP0:.+]] = insertvalue { i64, i16 } poison, i64 %a, 0
+    // CHECK: %[[TEMP1:.+]] = insertvalue { i64, i16 } %[[TEMP0]], i16 %b, 1
+    // CHECK: ret { i64, i16 } %[[TEMP1]]
+    let s = Struct2Desc(a, b);
+    s
+}
diff --git a/tests/codegen/option-niche-eq.rs b/tests/codegen/option-niche-eq.rs
index 7b95533..25ea5dd 100644
--- a/tests/codegen/option-niche-eq.rs
+++ b/tests/codegen/option-niche-eq.rs
@@ -7,7 +7,7 @@
 use core::ptr::NonNull;
 use core::num::NonZero;
 
-// CHECK-lABEL: @non_zero_eq
+// CHECK-LABEL: @non_zero_eq
 #[no_mangle]
 pub fn non_zero_eq(l: Option<NonZero<u32>>, r: Option<NonZero<u32>>) -> bool {
     // CHECK: start:
@@ -16,7 +16,7 @@
     l == r
 }
 
-// CHECK-lABEL: @non_zero_signed_eq
+// CHECK-LABEL: @non_zero_signed_eq
 #[no_mangle]
 pub fn non_zero_signed_eq(l: Option<NonZero<i64>>, r: Option<NonZero<i64>>) -> bool {
     // CHECK: start:
@@ -25,7 +25,7 @@
     l == r
 }
 
-// CHECK-lABEL: @non_null_eq
+// CHECK-LABEL: @non_null_eq
 #[no_mangle]
 pub fn non_null_eq(l: Option<NonNull<u8>>, r: Option<NonNull<u8>>) -> bool {
     // CHECK: start:
@@ -34,7 +34,7 @@
     l == r
 }
 
-// CHECK-lABEL: @ordering_eq
+// CHECK-LABEL: @ordering_eq
 #[no_mangle]
 pub fn ordering_eq(l: Option<Ordering>, r: Option<Ordering>) -> bool {
     // CHECK: start:
@@ -54,7 +54,7 @@
     G,
 }
 
-// CHECK-lABEL: @niche_eq
+// CHECK-LABEL: @niche_eq
 #[no_mangle]
 pub fn niche_eq(l: Option<EnumWithNiche>, r: Option<EnumWithNiche>) -> bool {
     // CHECK: start:
@@ -64,7 +64,7 @@
 }
 
 // FIXME: This should work too
-// // FIXME-CHECK-lABEL: @bool_eq
+// // FIXME-CHECK-LABEL: @bool_eq
 // #[no_mangle]
 // pub fn bool_eq(l: Option<bool>, r: Option<bool>) -> bool {
 //     // FIXME-CHECK: start:
diff --git a/tests/codegen/sanitizer/no-sanitize-inlining.rs b/tests/codegen/sanitizer/no-sanitize-inlining.rs
index 623bfa6..d5e4788 100644
--- a/tests/codegen/sanitizer/no-sanitize-inlining.rs
+++ b/tests/codegen/sanitizer/no-sanitize-inlining.rs
@@ -16,7 +16,7 @@
 // ASAN:       }
 //
 // LSAN-LABEL: define void @test
-// LSAN-NO:      call
+// LSAN-NOT:     call
 // LSAN:       }
 #[no_mangle]
 pub fn test(n: &mut u32) {
diff --git a/tests/codegen/simd/issue-120720-reduce-nan.rs b/tests/codegen/simd/issue-120720-reduce-nan.rs
index 2c6098c..0372582 100644
--- a/tests/codegen/simd/issue-120720-reduce-nan.rs
+++ b/tests/codegen/simd/issue-120720-reduce-nan.rs
@@ -8,7 +8,7 @@
 #![feature(stdarch_x86_avx512, avx512_target_feature)]
 use std::arch::x86_64::*;
 
-// CHECK-label: @demo(
+// CHECK-LABEL: @demo(
 #[no_mangle]
 #[target_feature(enable = "avx512f")] // Function-level target feature mismatches inhibit inlining
 pub unsafe fn demo() -> bool {
diff --git a/tests/codegen/vec-in-place.rs b/tests/codegen/vec-in-place.rs
index 7a175dc..c6b7736 100644
--- a/tests/codegen/vec-in-place.rs
+++ b/tests/codegen/vec-in-place.rs
@@ -90,3 +90,25 @@
     // correct.
     vec.into_iter().map(|e| unsafe { std::mem::transmute(e) }).collect()
 }
+
+// CHECK-LABEL: @vec_iterator_cast_unwrap_drop
+#[no_mangle]
+pub fn vec_iterator_cast_unwrap_drop(vec: Vec<Wrapper<String>>) -> Vec<String> {
+    // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+    // CHECK-NOT: call
+    // CHECK-NOT: %{{.*}} = mul
+    // CHECK-NOT: %{{.*}} = udiv
+
+    vec.into_iter().map(|Wrapper(e)| e).collect()
+}
+
+// CHECK-LABEL: @vec_iterator_cast_wrap_drop
+#[no_mangle]
+pub fn vec_iterator_cast_wrap_drop(vec: Vec<String>) -> Vec<Wrapper<String>> {
+    // CHECK-NOT: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}
+    // CHECK-NOT: call
+    // CHECK-NOT: %{{.*}} = mul
+    // CHECK-NOT: %{{.*}} = udiv
+
+    vec.into_iter().map(Wrapper).collect()
+}
diff --git a/tests/coverage/abort.cov-map b/tests/coverage/abort.cov-map
index 1c36f28..5673fa9 100644
--- a/tests/coverage/abort.cov-map
+++ b/tests/coverage/abort.cov-map
@@ -1,45 +1,37 @@
 Function name: abort::main
-Raw bytes (105): 0x[01, 01, 12, 01, 47, 05, 09, 03, 0d, 42, 11, 03, 0d, 11, 3e, 42, 11, 03, 0d, 3b, 15, 11, 3e, 42, 11, 03, 0d, 15, 36, 3b, 15, 11, 3e, 42, 11, 03, 0d, 05, 09, 0d, 01, 0e, 01, 01, 1b, 03, 02, 0b, 00, 18, 42, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 3e, 02, 0a, 00, 0b, 3b, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 36, 00, 31, 00, 32, 33, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 47, 01, 09, 00, 17, 0d, 02, 05, 01, 02]
+Raw bytes (89): 0x[01, 01, 0a, 01, 27, 05, 09, 03, 0d, 22, 11, 03, 0d, 03, 0d, 22, 15, 03, 0d, 03, 0d, 05, 09, 0d, 01, 0e, 01, 01, 1b, 03, 02, 0b, 00, 18, 22, 01, 0c, 00, 19, 11, 00, 1a, 02, 0a, 0e, 02, 0a, 00, 0b, 22, 02, 0c, 00, 19, 15, 00, 1a, 00, 31, 1a, 00, 31, 00, 32, 22, 04, 0c, 00, 19, 05, 00, 1a, 00, 31, 09, 00, 31, 00, 32, 27, 01, 09, 00, 17, 0d, 02, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 18
-- expression 0 operands: lhs = Counter(0), rhs = Expression(17, Add)
+Number of expressions: 10
+- expression 0 operands: lhs = Counter(0), rhs = Expression(9, Add)
 - expression 1 operands: lhs = Counter(1), rhs = Counter(2)
 - expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Expression(16, Sub), rhs = Counter(4)
+- expression 3 operands: lhs = Expression(8, Sub), rhs = Counter(4)
 - expression 4 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 5 operands: lhs = Counter(4), rhs = Expression(15, Sub)
-- expression 6 operands: lhs = Expression(16, Sub), rhs = Counter(4)
+- expression 5 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 6 operands: lhs = Expression(8, Sub), rhs = Counter(5)
 - expression 7 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 8 operands: lhs = Expression(14, Add), rhs = Counter(5)
-- expression 9 operands: lhs = Counter(4), rhs = Expression(15, Sub)
-- expression 10 operands: lhs = Expression(16, Sub), rhs = Counter(4)
-- expression 11 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 12 operands: lhs = Counter(5), rhs = Expression(13, Sub)
-- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(5)
-- expression 14 operands: lhs = Counter(4), rhs = Expression(15, Sub)
-- expression 15 operands: lhs = Expression(16, Sub), rhs = Counter(4)
-- expression 16 operands: lhs = Expression(0, Add), rhs = Counter(3)
-- expression 17 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 8 operands: lhs = Expression(0, Add), rhs = Counter(3)
+- expression 9 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 13
 - Code(Counter(0)) at (prev + 14, 1) to (start + 1, 27)
 - Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 24)
     = (c0 + (c1 + c2))
-- Code(Expression(16, Sub)) at (prev + 1, 12) to (start + 0, 25)
+- Code(Expression(8, Sub)) at (prev + 1, 12) to (start + 0, 25)
     = ((c0 + (c1 + c2)) - c3)
 - Code(Counter(4)) at (prev + 0, 26) to (start + 2, 10)
-- Code(Expression(15, Sub)) at (prev + 2, 10) to (start + 0, 11)
+- Code(Expression(3, Sub)) at (prev + 2, 10) to (start + 0, 11)
     = (((c0 + (c1 + c2)) - c3) - c4)
-- Code(Expression(14, Add)) at (prev + 2, 12) to (start + 0, 25)
-    = (c4 + (((c0 + (c1 + c2)) - c3) - c4))
+- Code(Expression(8, Sub)) at (prev + 2, 12) to (start + 0, 25)
+    = ((c0 + (c1 + c2)) - c3)
 - Code(Counter(5)) at (prev + 0, 26) to (start + 0, 49)
-- Code(Expression(13, Sub)) at (prev + 0, 49) to (start + 0, 50)
-    = ((c4 + (((c0 + (c1 + c2)) - c3) - c4)) - c5)
-- Code(Expression(12, Add)) at (prev + 4, 12) to (start + 0, 25)
-    = (c5 + ((c4 + (((c0 + (c1 + c2)) - c3) - c4)) - c5))
+- Code(Expression(6, Sub)) at (prev + 0, 49) to (start + 0, 50)
+    = (((c0 + (c1 + c2)) - c3) - c5)
+- Code(Expression(8, Sub)) at (prev + 4, 12) to (start + 0, 25)
+    = ((c0 + (c1 + c2)) - c3)
 - Code(Counter(1)) at (prev + 0, 26) to (start + 0, 49)
 - Code(Counter(2)) at (prev + 0, 49) to (start + 0, 50)
-- Code(Expression(17, Add)) at (prev + 1, 9) to (start + 0, 23)
+- Code(Expression(9, Add)) at (prev + 1, 9) to (start + 0, 23)
     = (c1 + c2)
 - Code(Counter(3)) at (prev + 2, 5) to (start + 1, 2)
 
diff --git a/tests/coverage/async.cov-map b/tests/coverage/async.cov-map
index e06d167..7d16372 100644
--- a/tests/coverage/async.cov-map
+++ b/tests/coverage/async.cov-map
@@ -7,19 +7,17 @@
 - Code(Counter(0)) at (prev + 9, 1) to (start + 0, 25)
 
 Function name: async::c::{closure#0}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 09, 19, 01, 0e, 05, 02, 09, 00, 0a, 02, 02, 09, 00, 0a, 07, 02, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 09, 19, 01, 0e, 05, 02, 09, 00, 0a, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 9, 25) to (start + 1, 14)
 - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 10)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2)
 
 Function name: async::d
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 11, 01, 00, 14]
@@ -188,19 +186,17 @@
     = ((c1 + c2) + c3)
 
 Function name: async::j::c
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 37, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 0a, 0d, 00, 0e, 07, 02, 05, 00, 06]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 37, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 0a, 0d, 00, 0e, 01, 02, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 55, 5) to (start + 1, 18)
 - Code(Counter(1)) at (prev + 2, 13) to (start + 0, 14)
 - Code(Expression(0, Sub)) at (prev + 10, 13) to (start + 0, 14)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 2, 5) to (start + 0, 6)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6)
 
 Function name: async::j::d
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 46, 05, 00, 17]
diff --git a/tests/coverage/async2.cov-map b/tests/coverage/async2.cov-map
index 28f319b..e39a1d7 100644
--- a/tests/coverage/async2.cov-map
+++ b/tests/coverage/async2.cov-map
@@ -7,17 +7,15 @@
 - Code(Counter(0)) at (prev + 13, 1) to (start + 0, 23)
 
 Function name: async2::async_func::{closure#0}
-Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 0d, 17, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 03, 01, 01, 00, 02]
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 0d, 17, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 1
-- expression 0 operands: lhs = Counter(1), rhs = Zero
+Number of expressions: 0
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 13, 23) to (start + 3, 9)
 - Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6)
 - Code(Zero) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + Zero)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: async2::async_func_just_println
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 15, 01, 00, 24]
@@ -44,15 +42,13 @@
 - Code(Counter(0)) at (prev + 25, 1) to (start + 7, 2)
 
 Function name: async2::non_async_func
-Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 05, 01, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 03, 01, 01, 00, 02]
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 05, 01, 03, 09, 05, 03, 0a, 02, 06, 00, 02, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 1
-- expression 0 operands: lhs = Counter(1), rhs = Zero
+Number of expressions: 0
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 5, 1) to (start + 3, 9)
 - Code(Counter(1)) at (prev + 3, 10) to (start + 2, 6)
 - Code(Zero) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + Zero)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/async_block.cov-map b/tests/coverage/async_block.cov-map
index 104133f..e54c15c 100644
--- a/tests/coverage/async_block.cov-map
+++ b/tests/coverage/async_block.cov-map
@@ -1,10 +1,9 @@
 Function name: async_block::main
-Raw bytes (38): 0x[01, 01, 02, 01, 05, 03, 05, 06, 01, 05, 01, 00, 0b, 05, 01, 09, 00, 0a, 03, 00, 0e, 00, 13, 05, 00, 14, 01, 16, 05, 07, 0a, 02, 06, 06, 03, 01, 00, 02]
+Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 05, 01, 00, 0b, 05, 01, 09, 00, 0a, 03, 00, 0e, 00, 13, 05, 00, 14, 01, 16, 05, 07, 0a, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(1)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 5, 1) to (start + 0, 11)
 - Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10)
@@ -12,21 +11,18 @@
     = (c0 + c1)
 - Code(Counter(1)) at (prev + 0, 20) to (start + 1, 22)
 - Code(Counter(1)) at (prev + 7, 10) to (start + 2, 6)
-- Code(Expression(1, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = ((c0 + c1) - c1)
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: async_block::main::{closure#0}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 07, 1c, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 07, 03, 09, 00, 0a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 07, 1c, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 7, 28) to (start + 1, 23)
 - Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14)
 - Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 9) to (start + 0, 10)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10)
 
diff --git a/tests/coverage/branch/generics.cov-map b/tests/coverage/branch/generics.cov-map
index d729b0c..2e5668c 100644
--- a/tests/coverage/branch/generics.cov-map
+++ b/tests/coverage/branch/generics.cov-map
@@ -1,10 +1,9 @@
 Function name: generics::print_size::<()>
-Raw bytes (35): 0x[01, 01, 02, 01, 05, 05, 02, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 07, 03, 01, 00, 02]
+Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 5
 - Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36)
 - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36)
@@ -13,16 +12,14 @@
 - Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: generics::print_size::<u32>
-Raw bytes (35): 0x[01, 01, 02, 01, 05, 05, 02, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 07, 03, 01, 00, 02]
+Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 5
 - Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36)
 - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36)
@@ -31,16 +28,14 @@
 - Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: generics::print_size::<u64>
-Raw bytes (35): 0x[01, 01, 02, 01, 05, 05, 02, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 07, 03, 01, 00, 02]
+Raw bytes (33): 0x[01, 01, 01, 01, 05, 05, 01, 06, 01, 01, 24, 20, 05, 02, 01, 08, 00, 24, 05, 00, 25, 02, 06, 02, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 5
 - Code(Counter(0)) at (prev + 6, 1) to (start + 1, 36)
 - Branch { true: Counter(1), false: Expression(0, Sub) } at (prev + 1, 8) to (start + 0, 36)
@@ -49,6 +44,5 @@
 - Code(Counter(1)) at (prev + 0, 37) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 12) to (start + 2, 6)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/branch/if-let.cov-map b/tests/coverage/branch/if-let.cov-map
index 0c7d986..0b098bc 100644
--- a/tests/coverage/branch/if-let.cov-map
+++ b/tests/coverage/branch/if-let.cov-map
@@ -1,10 +1,9 @@
 Function name: if_let::if_let
-Raw bytes (45): 0x[01, 01, 02, 05, 09, 09, 02, 07, 01, 0c, 01, 01, 10, 20, 02, 09, 03, 0c, 00, 13, 02, 00, 11, 00, 12, 05, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 09, 02, 0c, 02, 06, 07, 03, 05, 01, 02]
+Raw bytes (43): 0x[01, 01, 01, 05, 09, 07, 01, 0c, 01, 01, 10, 20, 02, 09, 03, 0c, 00, 13, 02, 00, 11, 00, 12, 05, 00, 16, 00, 1b, 02, 00, 1c, 02, 06, 09, 02, 0c, 02, 06, 05, 03, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub)
 Number of file 0 mappings: 7
 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
 - Branch { true: Expression(0, Sub), false: Counter(2) } at (prev + 3, 12) to (start + 0, 19)
@@ -16,8 +15,7 @@
 - Code(Expression(0, Sub)) at (prev + 0, 28) to (start + 2, 6)
     = (c1 - c2)
 - Code(Counter(2)) at (prev + 2, 12) to (start + 2, 6)
-- Code(Expression(1, Add)) at (prev + 3, 5) to (start + 1, 2)
-    = (c2 + (c1 - c2))
+- Code(Counter(1)) at (prev + 3, 5) to (start + 1, 2)
 
 Function name: if_let::if_let_chain
 Raw bytes (66): 0x[01, 01, 04, 01, 05, 05, 09, 0f, 0d, 05, 09, 0a, 01, 17, 01, 00, 33, 20, 02, 05, 01, 0c, 00, 13, 02, 00, 11, 00, 12, 01, 00, 16, 00, 17, 20, 0d, 09, 01, 10, 00, 17, 0d, 00, 15, 00, 16, 02, 00, 1a, 00, 1b, 0d, 01, 05, 03, 06, 0f, 03, 0c, 02, 06, 0b, 03, 05, 01, 02]
diff --git a/tests/coverage/branch/if.cov-map b/tests/coverage/branch/if.cov-map
index 50f6216..7f4ee98 100644
--- a/tests/coverage/branch/if.cov-map
+++ b/tests/coverage/branch/if.cov-map
@@ -24,51 +24,17 @@
     = (c4 + (c3 + (c1 - c2)))
 
 Function name: if::branch_not
-Raw bytes (224): 0x[01, 01, 29, 05, 09, 09, 02, a3, 01, 0d, 09, 02, a3, 01, 0d, 09, 02, 0d, 9e, 01, a3, 01, 0d, 09, 02, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 93, 01, 15, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 93, 01, 15, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 15, 8e, 01, 93, 01, 15, 11, 96, 01, 9b, 01, 11, 0d, 9e, 01, a3, 01, 0d, 09, 02, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 06, 00, 07, a3, 01, 01, 08, 00, 0a, 20, 9e, 01, 0d, 00, 08, 00, 0a, 9e, 01, 00, 0b, 02, 06, 0d, 02, 06, 00, 07, 9b, 01, 01, 08, 00, 0b, 20, 11, 96, 01, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 96, 01, 02, 06, 00, 07, 93, 01, 01, 08, 00, 0c, 20, 8e, 01, 15, 00, 08, 00, 0c, 8e, 01, 00, 0d, 02, 06, 15, 02, 06, 00, 07, 8b, 01, 01, 01, 00, 02]
+Raw bytes (116): 0x[01, 01, 07, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 05, 15, 05, 15, 12, 01, 0c, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 09, 01, 09, 00, 11, 02, 01, 06, 00, 07, 05, 01, 08, 00, 0a, 20, 0a, 0d, 00, 08, 00, 0a, 0a, 00, 0b, 02, 06, 0d, 02, 06, 00, 07, 05, 01, 08, 00, 0b, 20, 11, 12, 00, 08, 00, 0b, 11, 00, 0c, 02, 06, 12, 02, 06, 00, 07, 05, 01, 08, 00, 0c, 20, 1a, 15, 00, 08, 00, 0c, 1a, 00, 0d, 02, 06, 15, 02, 06, 00, 07, 05, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 41
+Number of expressions: 7
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 4 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 5 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 6 operands: lhs = Counter(3), rhs = Expression(39, Sub)
-- expression 7 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 8 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 9 operands: lhs = Expression(38, Add), rhs = Counter(4)
-- expression 10 operands: lhs = Counter(3), rhs = Expression(39, Sub)
-- expression 11 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 12 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 13 operands: lhs = Expression(38, Add), rhs = Counter(4)
-- expression 14 operands: lhs = Counter(3), rhs = Expression(39, Sub)
-- expression 15 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 16 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 17 operands: lhs = Counter(4), rhs = Expression(37, Sub)
-- expression 18 operands: lhs = Expression(38, Add), rhs = Counter(4)
-- expression 19 operands: lhs = Counter(3), rhs = Expression(39, Sub)
-- expression 20 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 21 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 22 operands: lhs = Expression(36, Add), rhs = Counter(5)
-- expression 23 operands: lhs = Counter(4), rhs = Expression(37, Sub)
-- expression 24 operands: lhs = Expression(38, Add), rhs = Counter(4)
-- expression 25 operands: lhs = Counter(3), rhs = Expression(39, Sub)
-- expression 26 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 27 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 28 operands: lhs = Expression(36, Add), rhs = Counter(5)
-- expression 29 operands: lhs = Counter(4), rhs = Expression(37, Sub)
-- expression 30 operands: lhs = Expression(38, Add), rhs = Counter(4)
-- expression 31 operands: lhs = Counter(3), rhs = Expression(39, Sub)
-- expression 32 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 33 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 34 operands: lhs = Counter(5), rhs = Expression(35, Sub)
-- expression 35 operands: lhs = Expression(36, Add), rhs = Counter(5)
-- expression 36 operands: lhs = Counter(4), rhs = Expression(37, Sub)
-- expression 37 operands: lhs = Expression(38, Add), rhs = Counter(4)
-- expression 38 operands: lhs = Counter(3), rhs = Expression(39, Sub)
-- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(3)
-- expression 40 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 2 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(1), rhs = Counter(4)
+- expression 4 operands: lhs = Counter(1), rhs = Counter(4)
+- expression 5 operands: lhs = Counter(1), rhs = Counter(5)
+- expression 6 operands: lhs = Counter(1), rhs = Counter(5)
 Number of file 0 mappings: 18
 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 3, 8) to (start + 0, 9)
@@ -78,60 +44,39 @@
 - Code(Counter(2)) at (prev + 1, 9) to (start + 0, 17)
 - Code(Expression(0, Sub)) at (prev + 1, 6) to (start + 0, 7)
     = (c1 - c2)
-- Code(Expression(40, Add)) at (prev + 1, 8) to (start + 0, 10)
-    = (c2 + (c1 - c2))
-- Branch { true: Expression(39, Sub), false: Counter(3) } at (prev + 0, 8) to (start + 0, 10)
-    true  = ((c2 + (c1 - c2)) - c3)
+- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 10)
+- Branch { true: Expression(2, Sub), false: Counter(3) } at (prev + 0, 8) to (start + 0, 10)
+    true  = (c1 - c3)
     false = c3
-- Code(Expression(39, Sub)) at (prev + 0, 11) to (start + 2, 6)
-    = ((c2 + (c1 - c2)) - c3)
+- Code(Expression(2, Sub)) at (prev + 0, 11) to (start + 2, 6)
+    = (c1 - c3)
 - Code(Counter(3)) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(38, Add)) at (prev + 1, 8) to (start + 0, 11)
-    = (c3 + ((c2 + (c1 - c2)) - c3))
-- Branch { true: Counter(4), false: Expression(37, Sub) } at (prev + 0, 8) to (start + 0, 11)
+- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 11)
+- Branch { true: Counter(4), false: Expression(4, Sub) } at (prev + 0, 8) to (start + 0, 11)
     true  = c4
-    false = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)
+    false = (c1 - c4)
 - Code(Counter(4)) at (prev + 0, 12) to (start + 2, 6)
-- Code(Expression(37, Sub)) at (prev + 2, 6) to (start + 0, 7)
-    = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)
-- Code(Expression(36, Add)) at (prev + 1, 8) to (start + 0, 12)
-    = (c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4))
-- Branch { true: Expression(35, Sub), false: Counter(5) } at (prev + 0, 8) to (start + 0, 12)
-    true  = ((c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)) - c5)
+- Code(Expression(4, Sub)) at (prev + 2, 6) to (start + 0, 7)
+    = (c1 - c4)
+- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 12)
+- Branch { true: Expression(6, Sub), false: Counter(5) } at (prev + 0, 8) to (start + 0, 12)
+    true  = (c1 - c5)
     false = c5
-- Code(Expression(35, Sub)) at (prev + 0, 13) to (start + 2, 6)
-    = ((c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)) - c5)
+- Code(Expression(6, Sub)) at (prev + 0, 13) to (start + 2, 6)
+    = (c1 - c5)
 - Code(Counter(5)) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(34, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c5 + ((c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)) - c5))
+- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: if::branch_not_as
-Raw bytes (124): 0x[01, 01, 16, 05, 09, 09, 02, 57, 0d, 09, 02, 57, 0d, 09, 02, 0d, 52, 57, 0d, 09, 02, 4f, 11, 0d, 52, 57, 0d, 09, 02, 4f, 11, 0d, 52, 57, 0d, 09, 02, 11, 4a, 4f, 11, 0d, 52, 57, 0d, 09, 02, 0e, 01, 1d, 01, 01, 10, 05, 03, 08, 00, 14, 20, 02, 09, 00, 08, 00, 14, 02, 00, 15, 02, 06, 09, 02, 06, 00, 07, 57, 01, 08, 00, 15, 20, 0d, 52, 00, 08, 00, 15, 0d, 00, 16, 02, 06, 52, 02, 06, 00, 07, 4f, 01, 08, 00, 16, 20, 4a, 11, 00, 08, 00, 16, 4a, 00, 17, 02, 06, 11, 02, 06, 00, 07, 47, 01, 01, 00, 02]
+Raw bytes (90): 0x[01, 01, 05, 05, 09, 05, 0d, 05, 0d, 05, 11, 05, 11, 0e, 01, 1d, 01, 01, 10, 05, 03, 08, 00, 14, 20, 02, 09, 00, 08, 00, 14, 02, 00, 15, 02, 06, 09, 02, 06, 00, 07, 05, 01, 08, 00, 15, 20, 0d, 0a, 00, 08, 00, 15, 0d, 00, 16, 02, 06, 0a, 02, 06, 00, 07, 05, 01, 08, 00, 16, 20, 12, 11, 00, 08, 00, 16, 12, 00, 17, 02, 06, 11, 02, 06, 00, 07, 05, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 22
+Number of expressions: 5
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Expression(21, Add), rhs = Counter(3)
-- expression 3 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 4 operands: lhs = Expression(21, Add), rhs = Counter(3)
-- expression 5 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 6 operands: lhs = Counter(3), rhs = Expression(20, Sub)
-- expression 7 operands: lhs = Expression(21, Add), rhs = Counter(3)
-- expression 8 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 9 operands: lhs = Expression(19, Add), rhs = Counter(4)
-- expression 10 operands: lhs = Counter(3), rhs = Expression(20, Sub)
-- expression 11 operands: lhs = Expression(21, Add), rhs = Counter(3)
-- expression 12 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 13 operands: lhs = Expression(19, Add), rhs = Counter(4)
-- expression 14 operands: lhs = Counter(3), rhs = Expression(20, Sub)
-- expression 15 operands: lhs = Expression(21, Add), rhs = Counter(3)
-- expression 16 operands: lhs = Counter(2), rhs = Expression(0, Sub)
-- expression 17 operands: lhs = Counter(4), rhs = Expression(18, Sub)
-- expression 18 operands: lhs = Expression(19, Add), rhs = Counter(4)
-- expression 19 operands: lhs = Counter(3), rhs = Expression(20, Sub)
-- expression 20 operands: lhs = Expression(21, Add), rhs = Counter(3)
-- expression 21 operands: lhs = Counter(2), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 2 operands: lhs = Counter(1), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(1), rhs = Counter(4)
+- expression 4 operands: lhs = Counter(1), rhs = Counter(4)
 Number of file 0 mappings: 14
 - Code(Counter(0)) at (prev + 29, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 3, 8) to (start + 0, 20)
@@ -141,24 +86,21 @@
 - Code(Expression(0, Sub)) at (prev + 0, 21) to (start + 2, 6)
     = (c1 - c2)
 - Code(Counter(2)) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(21, Add)) at (prev + 1, 8) to (start + 0, 21)
-    = (c2 + (c1 - c2))
-- Branch { true: Counter(3), false: Expression(20, Sub) } at (prev + 0, 8) to (start + 0, 21)
+- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 21)
+- Branch { true: Counter(3), false: Expression(2, Sub) } at (prev + 0, 8) to (start + 0, 21)
     true  = c3
-    false = ((c2 + (c1 - c2)) - c3)
+    false = (c1 - c3)
 - Code(Counter(3)) at (prev + 0, 22) to (start + 2, 6)
-- Code(Expression(20, Sub)) at (prev + 2, 6) to (start + 0, 7)
-    = ((c2 + (c1 - c2)) - c3)
-- Code(Expression(19, Add)) at (prev + 1, 8) to (start + 0, 22)
-    = (c3 + ((c2 + (c1 - c2)) - c3))
-- Branch { true: Expression(18, Sub), false: Counter(4) } at (prev + 0, 8) to (start + 0, 22)
-    true  = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)
+- Code(Expression(2, Sub)) at (prev + 2, 6) to (start + 0, 7)
+    = (c1 - c3)
+- Code(Counter(1)) at (prev + 1, 8) to (start + 0, 22)
+- Branch { true: Expression(4, Sub), false: Counter(4) } at (prev + 0, 8) to (start + 0, 22)
+    true  = (c1 - c4)
     false = c4
-- Code(Expression(18, Sub)) at (prev + 0, 23) to (start + 2, 6)
-    = ((c3 + ((c2 + (c1 - c2)) - c3)) - c4)
+- Code(Expression(4, Sub)) at (prev + 0, 23) to (start + 2, 6)
+    = (c1 - c4)
 - Code(Counter(4)) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(17, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c4 + ((c3 + ((c2 + (c1 - c2)) - c3)) - c4))
+- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: if::branch_or
 Raw bytes (56): 0x[01, 01, 04, 05, 09, 09, 0d, 0f, 11, 09, 0d, 08, 01, 35, 01, 01, 10, 05, 03, 08, 00, 09, 20, 09, 02, 00, 08, 00, 09, 02, 00, 0d, 00, 0e, 20, 0d, 11, 00, 0d, 00, 0e, 0f, 00, 0f, 02, 06, 11, 02, 0c, 02, 06, 0b, 03, 01, 00, 02]
diff --git a/tests/coverage/branch/lazy-boolean.cov-map b/tests/coverage/branch/lazy-boolean.cov-map
index e2d7310..09ce913 100644
--- a/tests/coverage/branch/lazy-boolean.cov-map
+++ b/tests/coverage/branch/lazy-boolean.cov-map
@@ -1,44 +1,35 @@
 Function name: lazy_boolean::branch_and
-Raw bytes (42): 0x[01, 01, 03, 09, 0a, 05, 09, 05, 09, 06, 01, 13, 01, 01, 10, 03, 04, 09, 00, 0a, 05, 00, 0d, 00, 0e, 20, 09, 0a, 00, 0d, 00, 0e, 09, 00, 12, 00, 13, 03, 01, 05, 01, 02]
+Raw bytes (38): 0x[01, 01, 01, 05, 09, 06, 01, 13, 01, 01, 10, 05, 04, 09, 00, 0a, 05, 00, 0d, 00, 0e, 20, 09, 02, 00, 0d, 00, 0e, 09, 00, 12, 00, 13, 05, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 3
-- expression 0 operands: lhs = Counter(2), rhs = Expression(2, Sub)
-- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 19, 1) to (start + 1, 16)
-- Code(Expression(0, Add)) at (prev + 4, 9) to (start + 0, 10)
-    = (c2 + (c1 - c2))
+- Code(Counter(1)) at (prev + 4, 9) to (start + 0, 10)
 - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
-- Branch { true: Counter(2), false: Expression(2, Sub) } at (prev + 0, 13) to (start + 0, 14)
+- Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14)
     true  = c2
     false = (c1 - c2)
 - Code(Counter(2)) at (prev + 0, 18) to (start + 0, 19)
-- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
-    = (c2 + (c1 - c2))
+- Code(Counter(1)) at (prev + 1, 5) to (start + 1, 2)
 
 Function name: lazy_boolean::branch_or
-Raw bytes (44): 0x[01, 01, 04, 09, 0e, 05, 09, 05, 09, 05, 09, 06, 01, 1b, 01, 01, 10, 03, 04, 09, 00, 0a, 05, 00, 0d, 00, 0e, 20, 09, 0e, 00, 0d, 00, 0e, 0e, 00, 12, 00, 13, 03, 01, 05, 01, 02]
+Raw bytes (38): 0x[01, 01, 01, 05, 09, 06, 01, 1b, 01, 01, 10, 05, 04, 09, 00, 0a, 05, 00, 0d, 00, 0e, 20, 09, 02, 00, 0d, 00, 0e, 02, 00, 12, 00, 13, 05, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 4
-- expression 0 operands: lhs = Counter(2), rhs = Expression(3, Sub)
-- expression 1 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 2 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(1), rhs = Counter(2)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 27, 1) to (start + 1, 16)
-- Code(Expression(0, Add)) at (prev + 4, 9) to (start + 0, 10)
-    = (c2 + (c1 - c2))
+- Code(Counter(1)) at (prev + 4, 9) to (start + 0, 10)
 - Code(Counter(1)) at (prev + 0, 13) to (start + 0, 14)
-- Branch { true: Counter(2), false: Expression(3, Sub) } at (prev + 0, 13) to (start + 0, 14)
+- Branch { true: Counter(2), false: Expression(0, Sub) } at (prev + 0, 13) to (start + 0, 14)
     true  = c2
     false = (c1 - c2)
-- Code(Expression(3, Sub)) at (prev + 0, 18) to (start + 0, 19)
+- Code(Expression(0, Sub)) at (prev + 0, 18) to (start + 0, 19)
     = (c1 - c2)
-- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 1, 2)
-    = (c2 + (c1 - c2))
+- Code(Counter(1)) at (prev + 1, 5) to (start + 1, 2)
 
 Function name: lazy_boolean::chain
 Raw bytes (149): 0x[01, 01, 13, 11, 07, 0b, 16, 15, 1a, 09, 0d, 05, 09, 05, 09, 09, 0d, 47, 25, 4b, 21, 19, 1d, 03, 19, 03, 19, 3e, 1d, 03, 19, 3e, 1d, 03, 19, 47, 25, 4b, 21, 19, 1d, 13, 01, 24, 01, 01, 10, 03, 04, 09, 00, 0a, 05, 00, 0d, 00, 12, 20, 09, 16, 00, 0d, 00, 12, 09, 00, 16, 00, 1b, 20, 0d, 1a, 00, 16, 00, 1b, 0d, 00, 1f, 00, 24, 20, 11, 15, 00, 1f, 00, 24, 11, 00, 28, 00, 2d, 03, 01, 05, 00, 11, 43, 03, 09, 00, 0a, 03, 00, 0d, 00, 12, 20, 19, 3e, 00, 0d, 00, 12, 3e, 00, 16, 00, 1b, 20, 1d, 3a, 00, 16, 00, 1b, 3a, 00, 1f, 00, 24, 20, 21, 25, 00, 1f, 00, 24, 25, 00, 28, 00, 2d, 43, 01, 05, 01, 02]
@@ -105,73 +96,71 @@
     = (((c6 + c7) + c8) + c9)
 
 Function name: lazy_boolean::nested_mixed
-Raw bytes (159): 0x[01, 01, 18, 07, 22, 11, 36, 3b, 11, 09, 0d, 26, 0d, 05, 09, 05, 09, 05, 09, 26, 0d, 05, 09, 09, 0d, 3b, 11, 09, 0d, 3b, 11, 09, 0d, 19, 5f, 1d, 21, 03, 15, 15, 19, 52, 56, 15, 19, 03, 15, 19, 5f, 1d, 21, 13, 01, 31, 01, 01, 10, 03, 04, 09, 00, 0a, 05, 00, 0e, 00, 13, 20, 09, 26, 00, 0e, 00, 13, 26, 00, 17, 00, 1d, 20, 0d, 22, 00, 17, 00, 1d, 3b, 00, 23, 00, 28, 20, 11, 36, 00, 23, 00, 28, 36, 00, 2c, 00, 33, 03, 01, 05, 00, 11, 5b, 03, 09, 00, 0a, 03, 00, 0e, 00, 13, 20, 15, 56, 00, 0e, 00, 13, 15, 00, 17, 00, 1c, 20, 19, 52, 00, 17, 00, 1c, 4f, 00, 22, 00, 28, 20, 1d, 21, 00, 22, 00, 28, 1d, 00, 2c, 00, 33, 5b, 01, 05, 01, 02]
+Raw bytes (155): 0x[01, 01, 16, 33, 1a, 09, 0d, 1e, 0d, 05, 09, 05, 09, 05, 09, 1e, 0d, 05, 09, 09, 0d, 33, 11, 09, 0d, 33, 11, 09, 0d, 19, 57, 1d, 21, 03, 15, 15, 19, 4a, 4e, 15, 19, 03, 15, 19, 57, 1d, 21, 13, 01, 31, 01, 01, 10, 03, 04, 09, 00, 0a, 05, 00, 0e, 00, 13, 20, 09, 1e, 00, 0e, 00, 13, 1e, 00, 17, 00, 1d, 20, 0d, 1a, 00, 17, 00, 1d, 33, 00, 23, 00, 28, 20, 11, 2e, 00, 23, 00, 28, 2e, 00, 2c, 00, 33, 03, 01, 05, 00, 11, 53, 03, 09, 00, 0a, 03, 00, 0e, 00, 13, 20, 15, 4e, 00, 0e, 00, 13, 15, 00, 17, 00, 1c, 20, 19, 4a, 00, 17, 00, 1c, 47, 00, 22, 00, 28, 20, 1d, 21, 00, 22, 00, 28, 1d, 00, 2c, 00, 33, 53, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 24
-- expression 0 operands: lhs = Expression(1, Add), rhs = Expression(8, Sub)
-- expression 1 operands: lhs = Counter(4), rhs = Expression(13, Sub)
-- expression 2 operands: lhs = Expression(14, Add), rhs = Counter(4)
-- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 4 operands: lhs = Expression(9, Sub), rhs = Counter(3)
+Number of expressions: 22
+- expression 0 operands: lhs = Expression(12, Add), rhs = Expression(6, Sub)
+- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 2 operands: lhs = Expression(7, Sub), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 4 operands: lhs = Counter(1), rhs = Counter(2)
 - expression 5 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 6 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 6 operands: lhs = Expression(7, Sub), rhs = Counter(3)
 - expression 7 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 8 operands: lhs = Expression(9, Sub), rhs = Counter(3)
-- expression 9 operands: lhs = Counter(1), rhs = Counter(2)
+- expression 8 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 9 operands: lhs = Expression(12, Add), rhs = Counter(4)
 - expression 10 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 11 operands: lhs = Expression(14, Add), rhs = Counter(4)
+- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(4)
 - expression 12 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(4)
-- expression 14 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 15 operands: lhs = Counter(6), rhs = Expression(23, Add)
-- expression 16 operands: lhs = Counter(7), rhs = Counter(8)
-- expression 17 operands: lhs = Expression(0, Add), rhs = Counter(5)
+- expression 13 operands: lhs = Counter(6), rhs = Expression(21, Add)
+- expression 14 operands: lhs = Counter(7), rhs = Counter(8)
+- expression 15 operands: lhs = Expression(0, Add), rhs = Counter(5)
+- expression 16 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 17 operands: lhs = Expression(18, Sub), rhs = Expression(19, Sub)
 - expression 18 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 19 operands: lhs = Expression(20, Sub), rhs = Expression(21, Sub)
-- expression 20 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 21 operands: lhs = Expression(0, Add), rhs = Counter(5)
-- expression 22 operands: lhs = Counter(6), rhs = Expression(23, Add)
-- expression 23 operands: lhs = Counter(7), rhs = Counter(8)
+- expression 19 operands: lhs = Expression(0, Add), rhs = Counter(5)
+- expression 20 operands: lhs = Counter(6), rhs = Expression(21, Add)
+- expression 21 operands: lhs = Counter(7), rhs = Counter(8)
 Number of file 0 mappings: 19
 - Code(Counter(0)) at (prev + 49, 1) to (start + 1, 16)
 - Code(Expression(0, Add)) at (prev + 4, 9) to (start + 0, 10)
-    = ((c4 + ((c2 + c3) - c4)) + ((c1 - c2) - c3))
+    = ((c2 + c3) + ((c1 - c2) - c3))
 - Code(Counter(1)) at (prev + 0, 14) to (start + 0, 19)
-- Branch { true: Counter(2), false: Expression(9, Sub) } at (prev + 0, 14) to (start + 0, 19)
+- Branch { true: Counter(2), false: Expression(7, Sub) } at (prev + 0, 14) to (start + 0, 19)
     true  = c2
     false = (c1 - c2)
-- Code(Expression(9, Sub)) at (prev + 0, 23) to (start + 0, 29)
+- Code(Expression(7, Sub)) at (prev + 0, 23) to (start + 0, 29)
     = (c1 - c2)
-- Branch { true: Counter(3), false: Expression(8, Sub) } at (prev + 0, 23) to (start + 0, 29)
+- Branch { true: Counter(3), false: Expression(6, Sub) } at (prev + 0, 23) to (start + 0, 29)
     true  = c3
     false = ((c1 - c2) - c3)
-- Code(Expression(14, Add)) at (prev + 0, 35) to (start + 0, 40)
+- Code(Expression(12, Add)) at (prev + 0, 35) to (start + 0, 40)
     = (c2 + c3)
-- Branch { true: Counter(4), false: Expression(13, Sub) } at (prev + 0, 35) to (start + 0, 40)
+- Branch { true: Counter(4), false: Expression(11, Sub) } at (prev + 0, 35) to (start + 0, 40)
     true  = c4
     false = ((c2 + c3) - c4)
-- Code(Expression(13, Sub)) at (prev + 0, 44) to (start + 0, 51)
+- Code(Expression(11, Sub)) at (prev + 0, 44) to (start + 0, 51)
     = ((c2 + c3) - c4)
 - Code(Expression(0, Add)) at (prev + 1, 5) to (start + 0, 17)
-    = ((c4 + ((c2 + c3) - c4)) + ((c1 - c2) - c3))
-- Code(Expression(22, Add)) at (prev + 3, 9) to (start + 0, 10)
+    = ((c2 + c3) + ((c1 - c2) - c3))
+- Code(Expression(20, Add)) at (prev + 3, 9) to (start + 0, 10)
     = (c6 + (c7 + c8))
 - Code(Expression(0, Add)) at (prev + 0, 14) to (start + 0, 19)
-    = ((c4 + ((c2 + c3) - c4)) + ((c1 - c2) - c3))
-- Branch { true: Counter(5), false: Expression(21, Sub) } at (prev + 0, 14) to (start + 0, 19)
+    = ((c2 + c3) + ((c1 - c2) - c3))
+- Branch { true: Counter(5), false: Expression(19, Sub) } at (prev + 0, 14) to (start + 0, 19)
     true  = c5
-    false = (((c4 + ((c2 + c3) - c4)) + ((c1 - c2) - c3)) - c5)
+    false = (((c2 + c3) + ((c1 - c2) - c3)) - c5)
 - Code(Counter(5)) at (prev + 0, 23) to (start + 0, 28)
-- Branch { true: Counter(6), false: Expression(20, Sub) } at (prev + 0, 23) to (start + 0, 28)
+- Branch { true: Counter(6), false: Expression(18, Sub) } at (prev + 0, 23) to (start + 0, 28)
     true  = c6
     false = (c5 - c6)
-- Code(Expression(19, Add)) at (prev + 0, 34) to (start + 0, 40)
-    = ((c5 - c6) + (((c4 + ((c2 + c3) - c4)) + ((c1 - c2) - c3)) - c5))
+- Code(Expression(17, Add)) at (prev + 0, 34) to (start + 0, 40)
+    = ((c5 - c6) + (((c2 + c3) + ((c1 - c2) - c3)) - c5))
 - Branch { true: Counter(7), false: Counter(8) } at (prev + 0, 34) to (start + 0, 40)
     true  = c7
     false = c8
 - Code(Counter(7)) at (prev + 0, 44) to (start + 0, 51)
-- Code(Expression(22, Add)) at (prev + 1, 5) to (start + 1, 2)
+- Code(Expression(20, Add)) at (prev + 1, 5) to (start + 1, 2)
     = (c6 + (c7 + c8))
 
diff --git a/tests/coverage/branch/let-else.cov-map b/tests/coverage/branch/let-else.cov-map
index c7f7add..0707993 100644
--- a/tests/coverage/branch/let-else.cov-map
+++ b/tests/coverage/branch/let-else.cov-map
@@ -1,10 +1,9 @@
 Function name: let_else::let_else
-Raw bytes (45): 0x[01, 01, 02, 05, 09, 09, 02, 07, 01, 0c, 01, 01, 10, 20, 02, 09, 03, 09, 00, 10, 02, 00, 0e, 00, 0f, 05, 00, 13, 00, 18, 09, 01, 09, 01, 0f, 02, 04, 05, 00, 0b, 07, 01, 01, 00, 02]
+Raw bytes (43): 0x[01, 01, 01, 05, 09, 07, 01, 0c, 01, 01, 10, 20, 02, 09, 03, 09, 00, 10, 02, 00, 0e, 00, 0f, 05, 00, 13, 00, 18, 09, 01, 09, 01, 0f, 02, 04, 05, 00, 0b, 05, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Counter(2), rhs = Expression(0, Sub)
 Number of file 0 mappings: 7
 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
 - Branch { true: Expression(0, Sub), false: Counter(2) } at (prev + 3, 9) to (start + 0, 16)
@@ -16,6 +15,5 @@
 - Code(Counter(2)) at (prev + 1, 9) to (start + 1, 15)
 - Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 0, 11)
     = (c1 - c2)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c2 + (c1 - c2))
+- Code(Counter(1)) at (prev + 1, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/branch/while.cov-map b/tests/coverage/branch/while.cov-map
index 5a3ef09..fd05bbb 100644
--- a/tests/coverage/branch/while.cov-map
+++ b/tests/coverage/branch/while.cov-map
@@ -1,42 +1,36 @@
 Function name: while::while_cond
-Raw bytes (42): 0x[01, 01, 03, 05, 09, 03, 09, 03, 09, 06, 01, 0c, 01, 01, 10, 05, 03, 09, 00, 12, 03, 01, 0b, 00, 10, 20, 09, 0a, 00, 0b, 00, 10, 09, 00, 11, 02, 06, 0a, 03, 01, 00, 02]
+Raw bytes (38): 0x[01, 01, 01, 05, 09, 06, 01, 0c, 01, 01, 10, 05, 03, 09, 00, 12, 03, 01, 0b, 00, 10, 20, 09, 05, 00, 0b, 00, 10, 09, 00, 11, 02, 06, 05, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 3
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(2)
-- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(2)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 12, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 3, 9) to (start + 0, 18)
 - Code(Expression(0, Add)) at (prev + 1, 11) to (start + 0, 16)
     = (c1 + c2)
-- Branch { true: Counter(2), false: Expression(2, Sub) } at (prev + 0, 11) to (start + 0, 16)
+- Branch { true: Counter(2), false: Counter(1) } at (prev + 0, 11) to (start + 0, 16)
     true  = c2
-    false = ((c1 + c2) - c2)
+    false = c1
 - Code(Counter(2)) at (prev + 0, 17) to (start + 2, 6)
-- Code(Expression(2, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = ((c1 + c2) - c2)
+- Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: while::while_cond_not
-Raw bytes (42): 0x[01, 01, 03, 05, 09, 03, 09, 03, 09, 06, 01, 15, 01, 01, 10, 05, 03, 09, 00, 12, 03, 01, 0b, 00, 14, 20, 09, 0a, 00, 0b, 00, 14, 09, 00, 15, 02, 06, 0a, 03, 01, 00, 02]
+Raw bytes (38): 0x[01, 01, 01, 05, 09, 06, 01, 15, 01, 01, 10, 05, 03, 09, 00, 12, 03, 01, 0b, 00, 14, 20, 09, 05, 00, 0b, 00, 14, 09, 00, 15, 02, 06, 05, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 3
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(1), rhs = Counter(2)
-- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(2)
-- expression 2 operands: lhs = Expression(0, Add), rhs = Counter(2)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 21, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 3, 9) to (start + 0, 18)
 - Code(Expression(0, Add)) at (prev + 1, 11) to (start + 0, 20)
     = (c1 + c2)
-- Branch { true: Counter(2), false: Expression(2, Sub) } at (prev + 0, 11) to (start + 0, 20)
+- Branch { true: Counter(2), false: Counter(1) } at (prev + 0, 11) to (start + 0, 20)
     true  = c2
-    false = ((c1 + c2) - c2)
+    false = c1
 - Code(Counter(2)) at (prev + 0, 21) to (start + 2, 6)
-- Code(Expression(2, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = ((c1 + c2) - c2)
+- Code(Counter(1)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: while::while_op_and
 Raw bytes (56): 0x[01, 01, 04, 05, 09, 03, 0d, 03, 0d, 11, 0d, 08, 01, 1e, 01, 01, 10, 05, 03, 09, 01, 12, 03, 02, 0b, 00, 10, 20, 0a, 0d, 00, 0b, 00, 10, 0a, 00, 14, 00, 19, 20, 09, 11, 00, 14, 00, 19, 09, 00, 1a, 03, 06, 0f, 04, 01, 00, 02]
diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map
index 9f0d337..f36ef7a 100644
--- a/tests/coverage/closure.cov-map
+++ b/tests/coverage/closure.cov-map
@@ -1,10 +1,9 @@
 Function name: closure::main
-Raw bytes (128): 0x[01, 01, 02, 01, 05, 05, 02, 18, 01, 09, 01, 0f, 0d, 01, 16, 0e, 06, 0a, 01, 10, 05, 13, 0d, 01, 1a, 0e, 06, 0a, 01, 10, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 06, 00, 07, 07, 01, 05, 03, 02]
+Raw bytes (126): 0x[01, 01, 01, 01, 05, 18, 01, 09, 01, 0f, 0d, 01, 16, 0e, 06, 0a, 01, 10, 05, 13, 0d, 01, 1a, 0e, 06, 0a, 01, 10, 05, 0c, 16, 01, 16, 05, 0d, 18, 01, 19, 09, 01, 1e, 01, 04, 09, 00, 29, 01, 01, 09, 00, 2d, 01, 01, 09, 00, 24, 01, 05, 09, 00, 24, 01, 02, 09, 00, 21, 01, 04, 09, 00, 21, 01, 04, 09, 00, 28, 01, 09, 09, 00, 32, 01, 04, 09, 00, 33, 01, 07, 09, 00, 4b, 01, 08, 09, 00, 48, 01, 0a, 09, 00, 47, 01, 08, 09, 00, 44, 01, 0a, 08, 00, 10, 05, 00, 11, 04, 06, 02, 04, 06, 00, 07, 01, 01, 05, 03, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 24
 - Code(Counter(0)) at (prev + 9, 1) to (start + 15, 13)
 - Code(Counter(0)) at (prev + 22, 14) to (start + 6, 10)
@@ -30,8 +29,7 @@
 - Code(Counter(1)) at (prev + 0, 17) to (start + 4, 6)
 - Code(Expression(0, Sub)) at (prev + 4, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 3, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 3, 2)
 
 Function name: closure::main::{closure#0} (unused)
 Raw bytes (24): 0x[01, 01, 00, 04, 00, 28, 05, 02, 14, 00, 02, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06]
@@ -77,72 +75,60 @@
 - Code(Zero) at (prev + 172, 13) to (start + 2, 14)
 
 Function name: closure::main::{closure#14}
-Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, b3, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 07, 01, 0d, 00, 0e]
+Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, b3, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 01, 0d, 00, 0e]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 179, 13) to (start + 2, 27)
 - Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37)
 - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 13) to (start + 0, 14)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14)
 
 Function name: closure::main::{closure#15}
-Raw bytes (41): 0x[01, 01, 03, 05, 0a, 01, 05, 01, 05, 06, 01, bb, 01, 09, 00, 0a, 03, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 03, 02, 09, 00, 0a]
+Raw bytes (37): 0x[01, 01, 01, 01, 05, 06, 01, bb, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 3
-- expression 0 operands: lhs = Counter(1), rhs = Expression(2, Sub)
-- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 187, 9) to (start + 0, 10)
-- Code(Expression(0, Add)) at (prev + 1, 13) to (start + 0, 21)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 21)
 - Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27)
 - Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37)
-- Code(Expression(2, Sub)) at (prev + 0, 47) to (start + 0, 51)
+- Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51)
     = (c0 - c1)
-- Code(Expression(0, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10)
 
 Function name: closure::main::{closure#16}
-Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, c5, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 07, 01, 0d, 00, 0e]
+Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, c5, 01, 0d, 02, 1b, 05, 02, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 01, 0d, 00, 0e]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 197, 13) to (start + 2, 27)
 - Code(Counter(1)) at (prev + 2, 30) to (start + 0, 37)
 - Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 13) to (start + 0, 14)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 14)
 
 Function name: closure::main::{closure#17}
-Raw bytes (41): 0x[01, 01, 03, 05, 0a, 01, 05, 01, 05, 06, 01, cd, 01, 09, 00, 0a, 03, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 0a, 00, 2f, 00, 33, 03, 02, 09, 00, 0a]
+Raw bytes (37): 0x[01, 01, 01, 01, 05, 06, 01, cd, 01, 09, 00, 0a, 01, 01, 0d, 00, 15, 01, 01, 11, 01, 1b, 05, 01, 1e, 00, 25, 02, 00, 2f, 00, 33, 01, 02, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 3
-- expression 0 operands: lhs = Counter(1), rhs = Expression(2, Sub)
-- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 2 operands: lhs = Counter(0), rhs = Counter(1)
+Number of expressions: 1
+- expression 0 operands: lhs = Counter(0), rhs = Counter(1)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 205, 9) to (start + 0, 10)
-- Code(Expression(0, Add)) at (prev + 1, 13) to (start + 0, 21)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 13) to (start + 0, 21)
 - Code(Counter(0)) at (prev + 1, 17) to (start + 1, 27)
 - Code(Counter(1)) at (prev + 1, 30) to (start + 0, 37)
-- Code(Expression(2, Sub)) at (prev + 0, 47) to (start + 0, 51)
+- Code(Expression(0, Sub)) at (prev + 0, 47) to (start + 0, 51)
     = (c0 - c1)
-- Code(Expression(0, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10)
 
 Function name: closure::main::{closure#18} (unused)
 Raw bytes (24): 0x[01, 01, 00, 04, 00, 19, 0d, 02, 1c, 00, 02, 1d, 02, 12, 00, 02, 12, 00, 13, 00, 01, 11, 01, 0e]
@@ -156,49 +142,43 @@
 - Code(Zero) at (prev + 1, 17) to (start + 1, 14)
 
 Function name: closure::main::{closure#19}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 07, 01, 11, 01, 0e]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 0d, 02, 1c, 05, 02, 1d, 02, 12, 02, 02, 12, 00, 13, 01, 01, 11, 01, 0e]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 67, 13) to (start + 2, 28)
 - Code(Counter(1)) at (prev + 2, 29) to (start + 2, 18)
 - Code(Expression(0, Sub)) at (prev + 2, 18) to (start + 0, 19)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 17) to (start + 1, 14)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 17) to (start + 1, 14)
 
 Function name: closure::main::{closure#1}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 52, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 52, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 82, 5) to (start + 2, 20)
 - Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10)
 - Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 9) to (start + 1, 6)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6)
 
 Function name: closure::main::{closure#2}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 68, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 07, 01, 09, 01, 06]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 68, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 104, 5) to (start + 2, 20)
 - Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10)
 - Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 9) to (start + 1, 6)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6)
 
 Function name: closure::main::{closure#3} (unused)
 Raw bytes (25): 0x[01, 01, 00, 04, 00, 81, 01, 05, 01, 14, 00, 01, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06]
diff --git a/tests/coverage/closure_bug.cov-map b/tests/coverage/closure_bug.cov-map
index 160b348..32e8db5 100644
--- a/tests/coverage/closure_bug.cov-map
+++ b/tests/coverage/closure_bug.cov-map
@@ -1,133 +1,84 @@
 Function name: closure_bug::main
-Raw bytes (201): 0x[01, 01, 26, 01, 05, 05, 02, 05, 02, 97, 01, 09, 05, 02, 09, 92, 01, 97, 01, 09, 05, 02, 09, 92, 01, 97, 01, 09, 05, 02, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 87, 01, 11, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 11, 82, 01, 87, 01, 11, 0d, 8a, 01, 8f, 01, 0d, 09, 92, 01, 97, 01, 09, 05, 02, 11, 01, 07, 01, 03, 0a, 01, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, 02, 00, 17, 00, 18, 97, 01, 02, 09, 00, 0a, 97, 01, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, 92, 01, 00, 17, 00, 18, 8f, 01, 02, 09, 00, 0a, 8f, 01, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, 8a, 01, 00, 17, 00, 18, 87, 01, 02, 09, 00, 0a, 87, 01, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, 82, 01, 00, 17, 00, 18, 7f, 01, 01, 00, 02]
+Raw bytes (97): 0x[01, 01, 04, 01, 05, 01, 09, 01, 0d, 01, 11, 11, 01, 07, 01, 03, 0a, 01, 09, 05, 01, 0e, 05, 01, 0f, 00, 17, 02, 00, 17, 00, 18, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 09, 01, 0f, 00, 17, 06, 00, 17, 00, 18, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 0d, 01, 0f, 00, 17, 0a, 00, 17, 00, 18, 01, 02, 09, 00, 0a, 01, 06, 05, 01, 0e, 11, 01, 0f, 00, 17, 0e, 00, 17, 00, 18, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 38
+Number of expressions: 4
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 3 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 4 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 5 operands: lhs = Counter(2), rhs = Expression(36, Sub)
-- expression 6 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 7 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 8 operands: lhs = Counter(2), rhs = Expression(36, Sub)
-- expression 9 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 10 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 11 operands: lhs = Expression(35, Add), rhs = Counter(3)
-- expression 12 operands: lhs = Counter(2), rhs = Expression(36, Sub)
-- expression 13 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 14 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 15 operands: lhs = Counter(3), rhs = Expression(34, Sub)
-- expression 16 operands: lhs = Expression(35, Add), rhs = Counter(3)
-- expression 17 operands: lhs = Counter(2), rhs = Expression(36, Sub)
-- expression 18 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 19 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 20 operands: lhs = Counter(3), rhs = Expression(34, Sub)
-- expression 21 operands: lhs = Expression(35, Add), rhs = Counter(3)
-- expression 22 operands: lhs = Counter(2), rhs = Expression(36, Sub)
-- expression 23 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 24 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 25 operands: lhs = Expression(33, Add), rhs = Counter(4)
-- expression 26 operands: lhs = Counter(3), rhs = Expression(34, Sub)
-- expression 27 operands: lhs = Expression(35, Add), rhs = Counter(3)
-- expression 28 operands: lhs = Counter(2), rhs = Expression(36, Sub)
-- expression 29 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 30 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 31 operands: lhs = Counter(4), rhs = Expression(32, Sub)
-- expression 32 operands: lhs = Expression(33, Add), rhs = Counter(4)
-- expression 33 operands: lhs = Counter(3), rhs = Expression(34, Sub)
-- expression 34 operands: lhs = Expression(35, Add), rhs = Counter(3)
-- expression 35 operands: lhs = Counter(2), rhs = Expression(36, Sub)
-- expression 36 operands: lhs = Expression(37, Add), rhs = Counter(2)
-- expression 37 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(0), rhs = Counter(4)
 Number of file 0 mappings: 17
 - Code(Counter(0)) at (prev + 7, 1) to (start + 3, 10)
 - Code(Counter(0)) at (prev + 9, 5) to (start + 1, 14)
 - Code(Counter(1)) at (prev + 1, 15) to (start + 0, 23)
 - Code(Expression(0, Sub)) at (prev + 0, 23) to (start + 0, 24)
     = (c0 - c1)
-- Code(Expression(37, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = (c1 + (c0 - c1))
-- Code(Expression(37, Add)) at (prev + 6, 5) to (start + 1, 14)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14)
 - Code(Counter(2)) at (prev + 1, 15) to (start + 0, 23)
-- Code(Expression(36, Sub)) at (prev + 0, 23) to (start + 0, 24)
-    = ((c1 + (c0 - c1)) - c2)
-- Code(Expression(35, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
-- Code(Expression(35, Add)) at (prev + 6, 5) to (start + 1, 14)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
+- Code(Expression(1, Sub)) at (prev + 0, 23) to (start + 0, 24)
+    = (c0 - c2)
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14)
 - Code(Counter(3)) at (prev + 1, 15) to (start + 0, 23)
-- Code(Expression(34, Sub)) at (prev + 0, 23) to (start + 0, 24)
-    = ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)
-- Code(Expression(33, Add)) at (prev + 2, 9) to (start + 0, 10)
-    = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
-- Code(Expression(33, Add)) at (prev + 6, 5) to (start + 1, 14)
-    = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
+- Code(Expression(2, Sub)) at (prev + 0, 23) to (start + 0, 24)
+    = (c0 - c3)
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 10)
+- Code(Counter(0)) at (prev + 6, 5) to (start + 1, 14)
 - Code(Counter(4)) at (prev + 1, 15) to (start + 0, 23)
-- Code(Expression(32, Sub)) at (prev + 0, 23) to (start + 0, 24)
-    = ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)
-- Code(Expression(31, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4))
+- Code(Expression(3, Sub)) at (prev + 0, 23) to (start + 0, 24)
+    = (c0 - c4)
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: closure_bug::main::{closure#0}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0e, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0e, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 14, 9) to (start + 0, 18)
 - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25)
 - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 0, 41) to (start + 0, 42)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 0, 41) to (start + 0, 42)
 
 Function name: closure_bug::main::{closure#1}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 17, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 17, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 23, 9) to (start + 0, 18)
 - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25)
 - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 0, 41) to (start + 0, 42)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 0, 41) to (start + 0, 42)
 
 Function name: closure_bug::main::{closure#2}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 20, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 20, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 32, 9) to (start + 0, 18)
 - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25)
 - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 0, 41) to (start + 0, 42)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 0, 41) to (start + 0, 42)
 
 Function name: closure_bug::main::{closure#3}
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 29, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 07, 00, 29, 00, 2a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 29, 09, 00, 12, 05, 00, 15, 00, 19, 02, 00, 23, 00, 28, 01, 00, 29, 00, 2a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 41, 9) to (start + 0, 18)
 - Code(Counter(1)) at (prev + 0, 21) to (start + 0, 25)
 - Code(Expression(0, Sub)) at (prev + 0, 35) to (start + 0, 40)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 0, 41) to (start + 0, 42)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 0, 41) to (start + 0, 42)
 
diff --git a/tests/coverage/closure_macro.cov-map b/tests/coverage/closure_macro.cov-map
index e43ed1f..fd8fbd9 100644
--- a/tests/coverage/closure_macro.cov-map
+++ b/tests/coverage/closure_macro.cov-map
@@ -7,12 +7,11 @@
 - Code(Counter(0)) at (prev + 29, 1) to (start + 2, 2)
 
 Function name: closure_macro::main
-Raw bytes (38): 0x[01, 01, 02, 01, 05, 05, 02, 06, 01, 21, 01, 01, 21, 02, 02, 09, 00, 12, 02, 00, 0f, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 01, 00, 02]
+Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 21, 01, 01, 21, 02, 02, 09, 00, 12, 02, 00, 0f, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 33, 1) to (start + 1, 33)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 18)
@@ -22,8 +21,7 @@
 - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: closure_macro::main::{closure#0}
 Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 10, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a]
diff --git a/tests/coverage/closure_macro_async.cov-map b/tests/coverage/closure_macro_async.cov-map
index 212b67a..43b5200 100644
--- a/tests/coverage/closure_macro_async.cov-map
+++ b/tests/coverage/closure_macro_async.cov-map
@@ -15,12 +15,11 @@
 - Code(Counter(0)) at (prev + 35, 1) to (start + 0, 43)
 
 Function name: closure_macro_async::test::{closure#0}
-Raw bytes (38): 0x[01, 01, 02, 01, 05, 05, 02, 06, 01, 23, 2b, 01, 21, 02, 02, 09, 00, 12, 02, 00, 0f, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 07, 03, 01, 00, 02]
+Raw bytes (36): 0x[01, 01, 01, 01, 05, 06, 01, 23, 2b, 01, 21, 02, 02, 09, 00, 12, 02, 00, 0f, 00, 54, 05, 00, 54, 00, 55, 02, 02, 09, 02, 0b, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 6
 - Code(Counter(0)) at (prev + 35, 43) to (start + 1, 33)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 18)
@@ -30,8 +29,7 @@
 - Code(Counter(1)) at (prev + 0, 84) to (start + 0, 85)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 2, 11)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
 Function name: closure_macro_async::test::{closure#0}::{closure#0}
 Raw bytes (35): 0x[01, 01, 03, 01, 05, 05, 0b, 09, 00, 05, 01, 12, 1c, 03, 21, 05, 04, 11, 01, 27, 02, 03, 11, 00, 16, 00, 00, 17, 00, 1e, 07, 02, 09, 00, 0a]
diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map
index a6a427a..1714377 100644
--- a/tests/coverage/conditions.cov-map
+++ b/tests/coverage/conditions.cov-map
@@ -1,259 +1,263 @@
 Function name: conditions::main
-Raw bytes (784): 0x[01, 01, 8e, 01, 09, 33, 37, 41, 3b, 3d, 35, 39, 05, 00, b7, 04, 09, 05, 00, 0d, 35, 26, 39, 0d, 35, 3b, 3d, 35, 39, 37, 41, 3b, 3d, 35, 39, b2, 04, 0d, b7, 04, 09, 05, 00, 45, 00, 83, 01, 49, 45, 00, 7e, 31, 83, 01, 49, 45, 00, 7a, 4d, 7e, 31, 83, 01, 49, 45, 00, 76, 51, 7a, 4d, 7e, 31, 83, 01, 49, 45, 00, a7, 01, 55, 4d, 51, a3, 01, 59, a7, 01, 55, 4d, 51, 49, 9f, 01, a3, 01, 59, a7, 01, 55, 4d, 51, 61, 00, e3, 01, 65, 61, 00, de, 01, 2d, e3, 01, 65, 61, 00, da, 01, 69, de, 01, 2d, e3, 01, 65, 61, 00, d6, 01, 6d, da, 01, 69, de, 01, 2d, e3, 01, 65, 61, 00, 8b, 02, 71, 69, 6d, 87, 02, 75, 8b, 02, 71, 69, 6d, ff, 01, 00, 65, 83, 02, 87, 02, 75, 8b, 02, 71, 69, 6d, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 79, 00, d7, 02, 7d, 79, 00, d2, 02, 29, d7, 02, 7d, 79, 00, ce, 02, 81, 01, d2, 02, 29, d7, 02, 7d, 79, 00, ca, 02, 85, 01, ce, 02, 81, 01, d2, 02, 29, d7, 02, 7d, 79, 00, f3, 03, 89, 01, 81, 01, 85, 01, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 11, 93, 04, 97, 04, 21, 9b, 04, 1d, 15, 19, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, de, 03, 15, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, da, 03, 19, de, 03, 15, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 9b, 04, 1d, 15, 19, 97, 04, 21, 9b, 04, 1d, 15, 19, 8f, 04, 9f, 04, 11, 93, 04, 97, 04, 21, 9b, 04, 1d, 15, 19, a3, 04, ae, 04, a7, 04, 31, ab, 04, 2d, 25, 29, b2, 04, 0d, b7, 04, 09, 05, 00, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 03, 09, 00, 0a, b7, 04, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, b2, 04, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 26, 00, 1d, 00, 2a, 22, 00, 2e, 00, 3c, 37, 00, 3d, 02, 0a, 41, 02, 0a, 00, 0b, 33, 01, 09, 01, 12, ae, 04, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 45, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 83, 01, 02, 08, 00, 15, 49, 00, 16, 02, 06, 7e, 02, 0f, 00, 1c, 7a, 01, 0c, 00, 19, 76, 00, 1d, 00, 2a, 72, 00, 2e, 00, 3c, a3, 01, 00, 3d, 02, 0a, 59, 02, 0a, 00, 0b, 9f, 01, 01, 09, 00, 17, 31, 02, 09, 00, 0f, 9b, 01, 03, 08, 00, 0c, 5d, 01, 0d, 01, 10, 61, 01, 11, 02, 0a, 00, 02, 0a, 00, 0b, e3, 01, 02, 0c, 00, 19, 65, 00, 1a, 02, 0a, de, 01, 04, 11, 00, 1e, da, 01, 01, 10, 00, 1d, d6, 01, 00, 21, 00, 2e, d2, 01, 00, 32, 00, 40, 87, 02, 00, 41, 02, 0e, 75, 02, 0e, 00, 0f, 83, 02, 01, 0d, 00, 1b, 2d, 02, 0d, 00, 13, 00, 02, 06, 00, 07, fb, 01, 02, 09, 01, 0c, 79, 01, 0d, 02, 06, 00, 02, 06, 00, 07, e7, 03, 02, 09, 00, 0a, d7, 02, 00, 10, 00, 1d, 7d, 00, 1e, 02, 06, d2, 02, 02, 0f, 00, 1c, ce, 02, 01, 0c, 00, 19, ca, 02, 00, 1d, 00, 2a, c6, 02, 00, 2e, 00, 3c, ef, 03, 00, 3d, 02, 0a, 8d, 01, 02, 0a, 00, 0b, eb, 03, 01, 09, 00, 17, 29, 02, 0d, 02, 0f, 8f, 04, 05, 09, 00, 0a, e7, 03, 00, 10, 00, 1d, 11, 00, 1e, 02, 06, e2, 03, 02, 0f, 00, 1c, de, 03, 01, 0c, 00, 19, da, 03, 00, 1d, 00, 2a, d6, 03, 00, 2e, 00, 3c, 97, 04, 00, 3d, 02, 0a, 21, 02, 0a, 00, 0b, 93, 04, 01, 09, 00, 17, 25, 02, 09, 00, 0f, 8b, 04, 02, 01, 00, 02]
+Raw bytes (799): 0x[01, 01, 94, 01, 09, 2b, 2f, 41, 33, 3d, 35, 39, 01, 09, 0d, 35, 1e, 39, 0d, 35, 33, 3d, 35, 39, 2f, 41, 33, 3d, 35, 39, ce, 04, 0d, 01, 09, 03, 49, 62, 31, 03, 49, 5e, 4d, 62, 31, 03, 49, 5a, 51, 5e, 4d, 62, 31, 03, 49, 87, 01, 55, 4d, 51, 83, 01, 59, 87, 01, 55, 4d, 51, 49, 7f, 83, 01, 59, 87, 01, 55, 4d, 51, 5d, 65, ae, 01, 2d, 5d, 65, aa, 01, 69, ae, 01, 2d, 5d, 65, a6, 01, 6d, aa, 01, 69, ae, 01, 2d, 5d, 65, f3, 02, 71, 69, 6d, ef, 02, 75, f3, 02, 71, 69, 6d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, da, 02, 81, 01, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, d6, 02, 85, 01, da, 02, 81, 01, de, 02, 29, e3, 02, 7d, e7, 02, 00, 65, eb, 02, ef, 02, 75, f3, 02, 71, 69, 6d, 8f, 04, 89, 01, 81, 01, 85, 01, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, 11, af, 04, b3, 04, 21, b7, 04, 1d, 15, 19, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, fa, 03, 15, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, f6, 03, 19, fa, 03, 15, fe, 03, 25, 83, 04, 11, 7d, 87, 04, 8b, 04, 8d, 01, 8f, 04, 89, 01, 81, 01, 85, 01, b7, 04, 1d, 15, 19, b3, 04, 21, b7, 04, 1d, 15, 19, ab, 04, bb, 04, 11, af, 04, b3, 04, 21, b7, 04, 1d, 15, 19, bf, 04, ca, 04, c3, 04, 31, c7, 04, 2d, 25, 29, ce, 04, 0d, 01, 09, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 03, 09, 00, 0a, 01, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, ce, 04, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 1e, 00, 1d, 00, 2a, 1a, 00, 2e, 00, 3c, 2f, 00, 3d, 02, 0a, 41, 02, 0a, 00, 0b, 2b, 01, 09, 01, 12, ca, 04, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 45, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 02, 08, 00, 15, 49, 00, 16, 02, 06, 62, 02, 0f, 00, 1c, 5e, 01, 0c, 00, 19, 5a, 00, 1d, 00, 2a, 56, 00, 2e, 00, 3c, 83, 01, 00, 3d, 02, 0a, 59, 02, 0a, 00, 0b, 7f, 01, 09, 00, 17, 31, 02, 09, 00, 0f, 7b, 03, 08, 00, 0c, 5d, 01, 0d, 01, 10, 61, 01, 11, 02, 0a, 00, 02, 0a, 00, 0b, 5d, 02, 0c, 00, 19, 65, 00, 1a, 02, 0a, ae, 01, 04, 11, 00, 1e, aa, 01, 01, 10, 00, 1d, a6, 01, 00, 21, 00, 2e, a2, 01, 00, 32, 00, 40, ef, 02, 00, 41, 02, 0e, 75, 02, 0e, 00, 0f, eb, 02, 01, 0d, 00, 1b, 2d, 02, 0d, 00, 13, 00, 02, 06, 00, 07, e3, 02, 02, 09, 01, 0c, 79, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 83, 04, 02, 09, 00, 0a, e3, 02, 00, 10, 00, 1d, 7d, 00, 1e, 02, 06, de, 02, 02, 0f, 00, 1c, da, 02, 01, 0c, 00, 19, d6, 02, 00, 1d, 00, 2a, d2, 02, 00, 2e, 00, 3c, 8b, 04, 00, 3d, 02, 0a, 8d, 01, 02, 0a, 00, 0b, 87, 04, 01, 09, 00, 17, 29, 02, 0d, 02, 0f, ab, 04, 05, 09, 00, 0a, 83, 04, 00, 10, 00, 1d, 11, 00, 1e, 02, 06, fe, 03, 02, 0f, 00, 1c, fa, 03, 01, 0c, 00, 19, f6, 03, 00, 1d, 00, 2a, f2, 03, 00, 2e, 00, 3c, b3, 04, 00, 3d, 02, 0a, 21, 02, 0a, 00, 0b, af, 04, 01, 09, 00, 17, 25, 02, 09, 00, 0f, a7, 04, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 142
-- expression 0 operands: lhs = Counter(2), rhs = Expression(12, Add)
-- expression 1 operands: lhs = Expression(13, Add), rhs = Counter(16)
-- expression 2 operands: lhs = Expression(14, Add), rhs = Counter(15)
+Number of expressions: 148
+- expression 0 operands: lhs = Counter(2), rhs = Expression(10, Add)
+- expression 1 operands: lhs = Expression(11, Add), rhs = Counter(16)
+- expression 2 operands: lhs = Expression(12, Add), rhs = Counter(15)
 - expression 3 operands: lhs = Counter(13), rhs = Counter(14)
-- expression 4 operands: lhs = Counter(1), rhs = Zero
-- expression 5 operands: lhs = Expression(141, Add), rhs = Counter(2)
-- expression 6 operands: lhs = Counter(1), rhs = Zero
+- expression 4 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 5 operands: lhs = Counter(3), rhs = Counter(13)
+- expression 6 operands: lhs = Expression(7, Sub), rhs = Counter(14)
 - expression 7 operands: lhs = Counter(3), rhs = Counter(13)
-- expression 8 operands: lhs = Expression(9, Sub), rhs = Counter(14)
-- expression 9 operands: lhs = Counter(3), rhs = Counter(13)
-- expression 10 operands: lhs = Expression(14, Add), rhs = Counter(15)
-- expression 11 operands: lhs = Counter(13), rhs = Counter(14)
-- expression 12 operands: lhs = Expression(13, Add), rhs = Counter(16)
-- expression 13 operands: lhs = Expression(14, Add), rhs = Counter(15)
-- expression 14 operands: lhs = Counter(13), rhs = Counter(14)
-- expression 15 operands: lhs = Expression(140, Sub), rhs = Counter(3)
-- expression 16 operands: lhs = Expression(141, Add), rhs = Counter(2)
-- expression 17 operands: lhs = Counter(1), rhs = Zero
-- expression 18 operands: lhs = Counter(17), rhs = Zero
-- expression 19 operands: lhs = Expression(32, Add), rhs = Counter(18)
-- expression 20 operands: lhs = Counter(17), rhs = Zero
-- expression 21 operands: lhs = Expression(31, Sub), rhs = Counter(12)
-- expression 22 operands: lhs = Expression(32, Add), rhs = Counter(18)
-- expression 23 operands: lhs = Counter(17), rhs = Zero
-- expression 24 operands: lhs = Expression(30, Sub), rhs = Counter(19)
-- expression 25 operands: lhs = Expression(31, Sub), rhs = Counter(12)
-- expression 26 operands: lhs = Expression(32, Add), rhs = Counter(18)
-- expression 27 operands: lhs = Counter(17), rhs = Zero
-- expression 28 operands: lhs = Expression(29, Sub), rhs = Counter(20)
-- expression 29 operands: lhs = Expression(30, Sub), rhs = Counter(19)
-- expression 30 operands: lhs = Expression(31, Sub), rhs = Counter(12)
-- expression 31 operands: lhs = Expression(32, Add), rhs = Counter(18)
-- expression 32 operands: lhs = Counter(17), rhs = Zero
-- expression 33 operands: lhs = Expression(41, Add), rhs = Counter(21)
-- expression 34 operands: lhs = Counter(19), rhs = Counter(20)
-- expression 35 operands: lhs = Expression(40, Add), rhs = Counter(22)
-- expression 36 operands: lhs = Expression(41, Add), rhs = Counter(21)
-- expression 37 operands: lhs = Counter(19), rhs = Counter(20)
-- expression 38 operands: lhs = Counter(18), rhs = Expression(39, Add)
-- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(22)
-- expression 40 operands: lhs = Expression(41, Add), rhs = Counter(21)
-- expression 41 operands: lhs = Counter(19), rhs = Counter(20)
-- expression 42 operands: lhs = Counter(24), rhs = Zero
-- expression 43 operands: lhs = Expression(56, Add), rhs = Counter(25)
-- expression 44 operands: lhs = Counter(24), rhs = Zero
-- expression 45 operands: lhs = Expression(55, Sub), rhs = Counter(11)
-- expression 46 operands: lhs = Expression(56, Add), rhs = Counter(25)
-- expression 47 operands: lhs = Counter(24), rhs = Zero
-- expression 48 operands: lhs = Expression(54, Sub), rhs = Counter(26)
-- expression 49 operands: lhs = Expression(55, Sub), rhs = Counter(11)
-- expression 50 operands: lhs = Expression(56, Add), rhs = Counter(25)
-- expression 51 operands: lhs = Counter(24), rhs = Zero
-- expression 52 operands: lhs = Expression(53, Sub), rhs = Counter(27)
-- expression 53 operands: lhs = Expression(54, Sub), rhs = Counter(26)
-- expression 54 operands: lhs = Expression(55, Sub), rhs = Counter(11)
-- expression 55 operands: lhs = Expression(56, Add), rhs = Counter(25)
-- expression 56 operands: lhs = Counter(24), rhs = Zero
-- expression 57 operands: lhs = Expression(66, Add), rhs = Counter(28)
-- expression 58 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 59 operands: lhs = Expression(65, Add), rhs = Counter(29)
-- expression 60 operands: lhs = Expression(66, Add), rhs = Counter(28)
-- expression 61 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 62 operands: lhs = Expression(63, Add), rhs = Zero
-- expression 63 operands: lhs = Counter(25), rhs = Expression(64, Add)
-- expression 64 operands: lhs = Expression(65, Add), rhs = Counter(29)
-- expression 65 operands: lhs = Expression(66, Add), rhs = Counter(28)
-- expression 66 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 67 operands: lhs = Counter(31), rhs = Expression(122, Add)
-- expression 68 operands: lhs = Expression(123, Add), rhs = Counter(35)
-- expression 69 operands: lhs = Expression(124, Add), rhs = Counter(34)
-- expression 70 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 71 operands: lhs = Counter(30), rhs = Zero
-- expression 72 operands: lhs = Expression(85, Add), rhs = Counter(31)
-- expression 73 operands: lhs = Counter(30), rhs = Zero
-- expression 74 operands: lhs = Expression(84, Sub), rhs = Counter(10)
-- expression 75 operands: lhs = Expression(85, Add), rhs = Counter(31)
-- expression 76 operands: lhs = Counter(30), rhs = Zero
-- expression 77 operands: lhs = Expression(83, Sub), rhs = Counter(32)
-- expression 78 operands: lhs = Expression(84, Sub), rhs = Counter(10)
-- expression 79 operands: lhs = Expression(85, Add), rhs = Counter(31)
-- expression 80 operands: lhs = Counter(30), rhs = Zero
-- expression 81 operands: lhs = Expression(82, Sub), rhs = Counter(33)
-- expression 82 operands: lhs = Expression(83, Sub), rhs = Counter(32)
-- expression 83 operands: lhs = Expression(84, Sub), rhs = Counter(10)
-- expression 84 operands: lhs = Expression(85, Add), rhs = Counter(31)
-- expression 85 operands: lhs = Counter(30), rhs = Zero
-- expression 86 operands: lhs = Expression(124, Add), rhs = Counter(34)
-- expression 87 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 88 operands: lhs = Expression(123, Add), rhs = Counter(35)
-- expression 89 operands: lhs = Expression(124, Add), rhs = Counter(34)
-- expression 90 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 91 operands: lhs = Counter(4), rhs = Expression(132, Add)
-- expression 92 operands: lhs = Expression(133, Add), rhs = Counter(8)
-- expression 93 operands: lhs = Expression(134, Add), rhs = Counter(7)
-- expression 94 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 95 operands: lhs = Counter(31), rhs = Expression(122, Add)
-- expression 96 operands: lhs = Expression(123, Add), rhs = Counter(35)
-- expression 97 operands: lhs = Expression(124, Add), rhs = Counter(34)
-- expression 98 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 99 operands: lhs = Expression(121, Add), rhs = Counter(4)
-- expression 100 operands: lhs = Counter(31), rhs = Expression(122, Add)
-- expression 101 operands: lhs = Expression(123, Add), rhs = Counter(35)
-- expression 102 operands: lhs = Expression(124, Add), rhs = Counter(34)
-- expression 103 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 104 operands: lhs = Expression(120, Sub), rhs = Counter(9)
-- expression 105 operands: lhs = Expression(121, Add), rhs = Counter(4)
-- expression 106 operands: lhs = Counter(31), rhs = Expression(122, Add)
-- expression 107 operands: lhs = Expression(123, Add), rhs = Counter(35)
-- expression 108 operands: lhs = Expression(124, Add), rhs = Counter(34)
-- expression 109 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 110 operands: lhs = Expression(119, Sub), rhs = Counter(5)
-- expression 111 operands: lhs = Expression(120, Sub), rhs = Counter(9)
-- expression 112 operands: lhs = Expression(121, Add), rhs = Counter(4)
-- expression 113 operands: lhs = Counter(31), rhs = Expression(122, Add)
-- expression 114 operands: lhs = Expression(123, Add), rhs = Counter(35)
-- expression 115 operands: lhs = Expression(124, Add), rhs = Counter(34)
+- expression 8 operands: lhs = Expression(12, Add), rhs = Counter(15)
+- expression 9 operands: lhs = Counter(13), rhs = Counter(14)
+- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(16)
+- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(15)
+- expression 12 operands: lhs = Counter(13), rhs = Counter(14)
+- expression 13 operands: lhs = Expression(147, Sub), rhs = Counter(3)
+- expression 14 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 15 operands: lhs = Expression(0, Add), rhs = Counter(18)
+- expression 16 operands: lhs = Expression(24, Sub), rhs = Counter(12)
+- expression 17 operands: lhs = Expression(0, Add), rhs = Counter(18)
+- expression 18 operands: lhs = Expression(23, Sub), rhs = Counter(19)
+- expression 19 operands: lhs = Expression(24, Sub), rhs = Counter(12)
+- expression 20 operands: lhs = Expression(0, Add), rhs = Counter(18)
+- expression 21 operands: lhs = Expression(22, Sub), rhs = Counter(20)
+- expression 22 operands: lhs = Expression(23, Sub), rhs = Counter(19)
+- expression 23 operands: lhs = Expression(24, Sub), rhs = Counter(12)
+- expression 24 operands: lhs = Expression(0, Add), rhs = Counter(18)
+- expression 25 operands: lhs = Expression(33, Add), rhs = Counter(21)
+- expression 26 operands: lhs = Counter(19), rhs = Counter(20)
+- expression 27 operands: lhs = Expression(32, Add), rhs = Counter(22)
+- expression 28 operands: lhs = Expression(33, Add), rhs = Counter(21)
+- expression 29 operands: lhs = Counter(19), rhs = Counter(20)
+- expression 30 operands: lhs = Counter(18), rhs = Expression(31, Add)
+- expression 31 operands: lhs = Expression(32, Add), rhs = Counter(22)
+- expression 32 operands: lhs = Expression(33, Add), rhs = Counter(21)
+- expression 33 operands: lhs = Counter(19), rhs = Counter(20)
+- expression 34 operands: lhs = Counter(23), rhs = Counter(25)
+- expression 35 operands: lhs = Expression(43, Sub), rhs = Counter(11)
+- expression 36 operands: lhs = Counter(23), rhs = Counter(25)
+- expression 37 operands: lhs = Expression(42, Sub), rhs = Counter(26)
+- expression 38 operands: lhs = Expression(43, Sub), rhs = Counter(11)
+- expression 39 operands: lhs = Counter(23), rhs = Counter(25)
+- expression 40 operands: lhs = Expression(41, Sub), rhs = Counter(27)
+- expression 41 operands: lhs = Expression(42, Sub), rhs = Counter(26)
+- expression 42 operands: lhs = Expression(43, Sub), rhs = Counter(11)
+- expression 43 operands: lhs = Counter(23), rhs = Counter(25)
+- expression 44 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 45 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 46 operands: lhs = Expression(91, Add), rhs = Counter(29)
+- expression 47 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 48 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 49 operands: lhs = Expression(89, Add), rhs = Zero
+- expression 50 operands: lhs = Counter(25), rhs = Expression(90, Add)
+- expression 51 operands: lhs = Expression(91, Add), rhs = Counter(29)
+- expression 52 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 53 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 54 operands: lhs = Counter(31), rhs = Expression(129, Add)
+- expression 55 operands: lhs = Expression(130, Add), rhs = Counter(35)
+- expression 56 operands: lhs = Expression(131, Add), rhs = Counter(34)
+- expression 57 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 58 operands: lhs = Expression(89, Add), rhs = Zero
+- expression 59 operands: lhs = Counter(25), rhs = Expression(90, Add)
+- expression 60 operands: lhs = Expression(91, Add), rhs = Counter(29)
+- expression 61 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 62 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 63 operands: lhs = Expression(88, Add), rhs = Counter(31)
+- expression 64 operands: lhs = Expression(89, Add), rhs = Zero
+- expression 65 operands: lhs = Counter(25), rhs = Expression(90, Add)
+- expression 66 operands: lhs = Expression(91, Add), rhs = Counter(29)
+- expression 67 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 68 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 69 operands: lhs = Expression(87, Sub), rhs = Counter(10)
+- expression 70 operands: lhs = Expression(88, Add), rhs = Counter(31)
+- expression 71 operands: lhs = Expression(89, Add), rhs = Zero
+- expression 72 operands: lhs = Counter(25), rhs = Expression(90, Add)
+- expression 73 operands: lhs = Expression(91, Add), rhs = Counter(29)
+- expression 74 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 75 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 76 operands: lhs = Expression(86, Sub), rhs = Counter(32)
+- expression 77 operands: lhs = Expression(87, Sub), rhs = Counter(10)
+- expression 78 operands: lhs = Expression(88, Add), rhs = Counter(31)
+- expression 79 operands: lhs = Expression(89, Add), rhs = Zero
+- expression 80 operands: lhs = Counter(25), rhs = Expression(90, Add)
+- expression 81 operands: lhs = Expression(91, Add), rhs = Counter(29)
+- expression 82 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 83 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 84 operands: lhs = Expression(85, Sub), rhs = Counter(33)
+- expression 85 operands: lhs = Expression(86, Sub), rhs = Counter(32)
+- expression 86 operands: lhs = Expression(87, Sub), rhs = Counter(10)
+- expression 87 operands: lhs = Expression(88, Add), rhs = Counter(31)
+- expression 88 operands: lhs = Expression(89, Add), rhs = Zero
+- expression 89 operands: lhs = Counter(25), rhs = Expression(90, Add)
+- expression 90 operands: lhs = Expression(91, Add), rhs = Counter(29)
+- expression 91 operands: lhs = Expression(92, Add), rhs = Counter(28)
+- expression 92 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 93 operands: lhs = Expression(131, Add), rhs = Counter(34)
+- expression 94 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 95 operands: lhs = Expression(130, Add), rhs = Counter(35)
+- expression 96 operands: lhs = Expression(131, Add), rhs = Counter(34)
+- expression 97 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 98 operands: lhs = Counter(4), rhs = Expression(139, Add)
+- expression 99 operands: lhs = Expression(140, Add), rhs = Counter(8)
+- expression 100 operands: lhs = Expression(141, Add), rhs = Counter(7)
+- expression 101 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 102 operands: lhs = Counter(31), rhs = Expression(129, Add)
+- expression 103 operands: lhs = Expression(130, Add), rhs = Counter(35)
+- expression 104 operands: lhs = Expression(131, Add), rhs = Counter(34)
+- expression 105 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 106 operands: lhs = Expression(128, Add), rhs = Counter(4)
+- expression 107 operands: lhs = Counter(31), rhs = Expression(129, Add)
+- expression 108 operands: lhs = Expression(130, Add), rhs = Counter(35)
+- expression 109 operands: lhs = Expression(131, Add), rhs = Counter(34)
+- expression 110 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 111 operands: lhs = Expression(127, Sub), rhs = Counter(9)
+- expression 112 operands: lhs = Expression(128, Add), rhs = Counter(4)
+- expression 113 operands: lhs = Counter(31), rhs = Expression(129, Add)
+- expression 114 operands: lhs = Expression(130, Add), rhs = Counter(35)
+- expression 115 operands: lhs = Expression(131, Add), rhs = Counter(34)
 - expression 116 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 117 operands: lhs = Expression(118, Sub), rhs = Counter(6)
-- expression 118 operands: lhs = Expression(119, Sub), rhs = Counter(5)
-- expression 119 operands: lhs = Expression(120, Sub), rhs = Counter(9)
-- expression 120 operands: lhs = Expression(121, Add), rhs = Counter(4)
-- expression 121 operands: lhs = Counter(31), rhs = Expression(122, Add)
-- expression 122 operands: lhs = Expression(123, Add), rhs = Counter(35)
-- expression 123 operands: lhs = Expression(124, Add), rhs = Counter(34)
-- expression 124 operands: lhs = Counter(32), rhs = Counter(33)
-- expression 125 operands: lhs = Expression(134, Add), rhs = Counter(7)
-- expression 126 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 127 operands: lhs = Expression(133, Add), rhs = Counter(8)
-- expression 128 operands: lhs = Expression(134, Add), rhs = Counter(7)
-- expression 129 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 130 operands: lhs = Expression(131, Add), rhs = Expression(135, Add)
-- expression 131 operands: lhs = Counter(4), rhs = Expression(132, Add)
-- expression 132 operands: lhs = Expression(133, Add), rhs = Counter(8)
-- expression 133 operands: lhs = Expression(134, Add), rhs = Counter(7)
-- expression 134 operands: lhs = Counter(5), rhs = Counter(6)
-- expression 135 operands: lhs = Expression(136, Add), rhs = Expression(139, Sub)
-- expression 136 operands: lhs = Expression(137, Add), rhs = Counter(12)
-- expression 137 operands: lhs = Expression(138, Add), rhs = Counter(11)
-- expression 138 operands: lhs = Counter(9), rhs = Counter(10)
-- expression 139 operands: lhs = Expression(140, Sub), rhs = Counter(3)
-- expression 140 operands: lhs = Expression(141, Add), rhs = Counter(2)
-- expression 141 operands: lhs = Counter(1), rhs = Zero
+- expression 117 operands: lhs = Expression(126, Sub), rhs = Counter(5)
+- expression 118 operands: lhs = Expression(127, Sub), rhs = Counter(9)
+- expression 119 operands: lhs = Expression(128, Add), rhs = Counter(4)
+- expression 120 operands: lhs = Counter(31), rhs = Expression(129, Add)
+- expression 121 operands: lhs = Expression(130, Add), rhs = Counter(35)
+- expression 122 operands: lhs = Expression(131, Add), rhs = Counter(34)
+- expression 123 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 124 operands: lhs = Expression(125, Sub), rhs = Counter(6)
+- expression 125 operands: lhs = Expression(126, Sub), rhs = Counter(5)
+- expression 126 operands: lhs = Expression(127, Sub), rhs = Counter(9)
+- expression 127 operands: lhs = Expression(128, Add), rhs = Counter(4)
+- expression 128 operands: lhs = Counter(31), rhs = Expression(129, Add)
+- expression 129 operands: lhs = Expression(130, Add), rhs = Counter(35)
+- expression 130 operands: lhs = Expression(131, Add), rhs = Counter(34)
+- expression 131 operands: lhs = Counter(32), rhs = Counter(33)
+- expression 132 operands: lhs = Expression(141, Add), rhs = Counter(7)
+- expression 133 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 134 operands: lhs = Expression(140, Add), rhs = Counter(8)
+- expression 135 operands: lhs = Expression(141, Add), rhs = Counter(7)
+- expression 136 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 137 operands: lhs = Expression(138, Add), rhs = Expression(142, Add)
+- expression 138 operands: lhs = Counter(4), rhs = Expression(139, Add)
+- expression 139 operands: lhs = Expression(140, Add), rhs = Counter(8)
+- expression 140 operands: lhs = Expression(141, Add), rhs = Counter(7)
+- expression 141 operands: lhs = Counter(5), rhs = Counter(6)
+- expression 142 operands: lhs = Expression(143, Add), rhs = Expression(146, Sub)
+- expression 143 operands: lhs = Expression(144, Add), rhs = Counter(12)
+- expression 144 operands: lhs = Expression(145, Add), rhs = Counter(11)
+- expression 145 operands: lhs = Counter(9), rhs = Counter(10)
+- expression 146 operands: lhs = Expression(147, Sub), rhs = Counter(3)
+- expression 147 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 68
 - Code(Counter(0)) at (prev + 3, 1) to (start + 2, 12)
 - Code(Counter(1)) at (prev + 2, 13) to (start + 2, 6)
 - Code(Zero) at (prev + 2, 6) to (start + 0, 7)
 - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 0, 10)
     = (c2 + (((c13 + c14) + c15) + c16))
-- Code(Expression(141, Add)) at (prev + 0, 16) to (start + 0, 29)
-    = (c1 + Zero)
+- Code(Counter(0)) at (prev + 0, 16) to (start + 0, 29)
 - Code(Counter(2)) at (prev + 1, 9) to (start + 1, 10)
-- Code(Expression(140, Sub)) at (prev + 2, 15) to (start + 0, 28)
-    = ((c1 + Zero) - c2)
+- Code(Expression(147, Sub)) at (prev + 2, 15) to (start + 0, 28)
+    = (c0 - c2)
 - Code(Counter(3)) at (prev + 1, 12) to (start + 0, 25)
-- Code(Expression(9, Sub)) at (prev + 0, 29) to (start + 0, 42)
+- Code(Expression(7, Sub)) at (prev + 0, 29) to (start + 0, 42)
     = (c3 - c13)
-- Code(Expression(8, Sub)) at (prev + 0, 46) to (start + 0, 60)
+- Code(Expression(6, Sub)) at (prev + 0, 46) to (start + 0, 60)
     = ((c3 - c13) - c14)
-- Code(Expression(13, Add)) at (prev + 0, 61) to (start + 2, 10)
+- Code(Expression(11, Add)) at (prev + 0, 61) to (start + 2, 10)
     = ((c13 + c14) + c15)
 - Code(Counter(16)) at (prev + 2, 10) to (start + 0, 11)
-- Code(Expression(12, Add)) at (prev + 1, 9) to (start + 1, 18)
+- Code(Expression(10, Add)) at (prev + 1, 9) to (start + 1, 18)
     = (((c13 + c14) + c15) + c16)
-- Code(Expression(139, Sub)) at (prev + 3, 9) to (start + 0, 15)
-    = (((c1 + Zero) - c2) - c3)
+- Code(Expression(146, Sub)) at (prev + 3, 9) to (start + 0, 15)
+    = ((c0 - c2) - c3)
 - Code(Expression(0, Add)) at (prev + 3, 9) to (start + 1, 12)
     = (c2 + (((c13 + c14) + c15) + c16))
 - Code(Counter(17)) at (prev + 1, 13) to (start + 2, 6)
 - Code(Zero) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(32, Add)) at (prev + 2, 8) to (start + 0, 21)
-    = (c17 + Zero)
+- Code(Expression(0, Add)) at (prev + 2, 8) to (start + 0, 21)
+    = (c2 + (((c13 + c14) + c15) + c16))
 - Code(Counter(18)) at (prev + 0, 22) to (start + 2, 6)
-- Code(Expression(31, Sub)) at (prev + 2, 15) to (start + 0, 28)
-    = ((c17 + Zero) - c18)
-- Code(Expression(30, Sub)) at (prev + 1, 12) to (start + 0, 25)
-    = (((c17 + Zero) - c18) - c12)
-- Code(Expression(29, Sub)) at (prev + 0, 29) to (start + 0, 42)
-    = ((((c17 + Zero) - c18) - c12) - c19)
-- Code(Expression(28, Sub)) at (prev + 0, 46) to (start + 0, 60)
-    = (((((c17 + Zero) - c18) - c12) - c19) - c20)
-- Code(Expression(40, Add)) at (prev + 0, 61) to (start + 2, 10)
+- Code(Expression(24, Sub)) at (prev + 2, 15) to (start + 0, 28)
+    = ((c2 + (((c13 + c14) + c15) + c16)) - c18)
+- Code(Expression(23, Sub)) at (prev + 1, 12) to (start + 0, 25)
+    = (((c2 + (((c13 + c14) + c15) + c16)) - c18) - c12)
+- Code(Expression(22, Sub)) at (prev + 0, 29) to (start + 0, 42)
+    = ((((c2 + (((c13 + c14) + c15) + c16)) - c18) - c12) - c19)
+- Code(Expression(21, Sub)) at (prev + 0, 46) to (start + 0, 60)
+    = (((((c2 + (((c13 + c14) + c15) + c16)) - c18) - c12) - c19) - c20)
+- Code(Expression(32, Add)) at (prev + 0, 61) to (start + 2, 10)
     = ((c19 + c20) + c21)
 - Code(Counter(22)) at (prev + 2, 10) to (start + 0, 11)
-- Code(Expression(39, Add)) at (prev + 1, 9) to (start + 0, 23)
+- Code(Expression(31, Add)) at (prev + 1, 9) to (start + 0, 23)
     = (((c19 + c20) + c21) + c22)
 - Code(Counter(12)) at (prev + 2, 9) to (start + 0, 15)
-- Code(Expression(38, Add)) at (prev + 3, 8) to (start + 0, 12)
+- Code(Expression(30, Add)) at (prev + 3, 8) to (start + 0, 12)
     = (c18 + (((c19 + c20) + c21) + c22))
 - Code(Counter(23)) at (prev + 1, 13) to (start + 1, 16)
 - Code(Counter(24)) at (prev + 1, 17) to (start + 2, 10)
 - Code(Zero) at (prev + 2, 10) to (start + 0, 11)
-- Code(Expression(56, Add)) at (prev + 2, 12) to (start + 0, 25)
-    = (c24 + Zero)
+- Code(Counter(23)) at (prev + 2, 12) to (start + 0, 25)
 - Code(Counter(25)) at (prev + 0, 26) to (start + 2, 10)
-- Code(Expression(55, Sub)) at (prev + 4, 17) to (start + 0, 30)
-    = ((c24 + Zero) - c25)
-- Code(Expression(54, Sub)) at (prev + 1, 16) to (start + 0, 29)
-    = (((c24 + Zero) - c25) - c11)
-- Code(Expression(53, Sub)) at (prev + 0, 33) to (start + 0, 46)
-    = ((((c24 + Zero) - c25) - c11) - c26)
-- Code(Expression(52, Sub)) at (prev + 0, 50) to (start + 0, 64)
-    = (((((c24 + Zero) - c25) - c11) - c26) - c27)
-- Code(Expression(65, Add)) at (prev + 0, 65) to (start + 2, 14)
+- Code(Expression(43, Sub)) at (prev + 4, 17) to (start + 0, 30)
+    = (c23 - c25)
+- Code(Expression(42, Sub)) at (prev + 1, 16) to (start + 0, 29)
+    = ((c23 - c25) - c11)
+- Code(Expression(41, Sub)) at (prev + 0, 33) to (start + 0, 46)
+    = (((c23 - c25) - c11) - c26)
+- Code(Expression(40, Sub)) at (prev + 0, 50) to (start + 0, 64)
+    = ((((c23 - c25) - c11) - c26) - c27)
+- Code(Expression(91, Add)) at (prev + 0, 65) to (start + 2, 14)
     = ((c26 + c27) + c28)
 - Code(Counter(29)) at (prev + 2, 14) to (start + 0, 15)
-- Code(Expression(64, Add)) at (prev + 1, 13) to (start + 0, 27)
+- Code(Expression(90, Add)) at (prev + 1, 13) to (start + 0, 27)
     = (((c26 + c27) + c28) + c29)
 - Code(Counter(11)) at (prev + 2, 13) to (start + 0, 19)
 - Code(Zero) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(62, Add)) at (prev + 2, 9) to (start + 1, 12)
+- Code(Expression(88, Add)) at (prev + 2, 9) to (start + 1, 12)
     = ((c25 + (((c26 + c27) + c28) + c29)) + Zero)
 - Code(Counter(30)) at (prev + 1, 13) to (start + 2, 6)
 - Code(Zero) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(121, Add)) at (prev + 2, 9) to (start + 0, 10)
+- Code(Expression(128, Add)) at (prev + 2, 9) to (start + 0, 10)
     = (c31 + (((c32 + c33) + c34) + c35))
-- Code(Expression(85, Add)) at (prev + 0, 16) to (start + 0, 29)
-    = (c30 + Zero)
+- Code(Expression(88, Add)) at (prev + 0, 16) to (start + 0, 29)
+    = ((c25 + (((c26 + c27) + c28) + c29)) + Zero)
 - Code(Counter(31)) at (prev + 0, 30) to (start + 2, 6)
-- Code(Expression(84, Sub)) at (prev + 2, 15) to (start + 0, 28)
-    = ((c30 + Zero) - c31)
-- Code(Expression(83, Sub)) at (prev + 1, 12) to (start + 0, 25)
-    = (((c30 + Zero) - c31) - c10)
-- Code(Expression(82, Sub)) at (prev + 0, 29) to (start + 0, 42)
-    = ((((c30 + Zero) - c31) - c10) - c32)
-- Code(Expression(81, Sub)) at (prev + 0, 46) to (start + 0, 60)
-    = (((((c30 + Zero) - c31) - c10) - c32) - c33)
-- Code(Expression(123, Add)) at (prev + 0, 61) to (start + 2, 10)
+- Code(Expression(87, Sub)) at (prev + 2, 15) to (start + 0, 28)
+    = (((c25 + (((c26 + c27) + c28) + c29)) + Zero) - c31)
+- Code(Expression(86, Sub)) at (prev + 1, 12) to (start + 0, 25)
+    = ((((c25 + (((c26 + c27) + c28) + c29)) + Zero) - c31) - c10)
+- Code(Expression(85, Sub)) at (prev + 0, 29) to (start + 0, 42)
+    = (((((c25 + (((c26 + c27) + c28) + c29)) + Zero) - c31) - c10) - c32)
+- Code(Expression(84, Sub)) at (prev + 0, 46) to (start + 0, 60)
+    = ((((((c25 + (((c26 + c27) + c28) + c29)) + Zero) - c31) - c10) - c32) - c33)
+- Code(Expression(130, Add)) at (prev + 0, 61) to (start + 2, 10)
     = ((c32 + c33) + c34)
 - Code(Counter(35)) at (prev + 2, 10) to (start + 0, 11)
-- Code(Expression(122, Add)) at (prev + 1, 9) to (start + 0, 23)
+- Code(Expression(129, Add)) at (prev + 1, 9) to (start + 0, 23)
     = (((c32 + c33) + c34) + c35)
 - Code(Counter(10)) at (prev + 2, 13) to (start + 2, 15)
-- Code(Expression(131, Add)) at (prev + 5, 9) to (start + 0, 10)
+- Code(Expression(138, Add)) at (prev + 5, 9) to (start + 0, 10)
     = (c4 + (((c5 + c6) + c7) + c8))
-- Code(Expression(121, Add)) at (prev + 0, 16) to (start + 0, 29)
+- Code(Expression(128, Add)) at (prev + 0, 16) to (start + 0, 29)
     = (c31 + (((c32 + c33) + c34) + c35))
 - Code(Counter(4)) at (prev + 0, 30) to (start + 2, 6)
-- Code(Expression(120, Sub)) at (prev + 2, 15) to (start + 0, 28)
+- Code(Expression(127, Sub)) at (prev + 2, 15) to (start + 0, 28)
     = ((c31 + (((c32 + c33) + c34) + c35)) - c4)
-- Code(Expression(119, Sub)) at (prev + 1, 12) to (start + 0, 25)
+- Code(Expression(126, Sub)) at (prev + 1, 12) to (start + 0, 25)
     = (((c31 + (((c32 + c33) + c34) + c35)) - c4) - c9)
-- Code(Expression(118, Sub)) at (prev + 0, 29) to (start + 0, 42)
+- Code(Expression(125, Sub)) at (prev + 0, 29) to (start + 0, 42)
     = ((((c31 + (((c32 + c33) + c34) + c35)) - c4) - c9) - c5)
-- Code(Expression(117, Sub)) at (prev + 0, 46) to (start + 0, 60)
+- Code(Expression(124, Sub)) at (prev + 0, 46) to (start + 0, 60)
     = (((((c31 + (((c32 + c33) + c34) + c35)) - c4) - c9) - c5) - c6)
-- Code(Expression(133, Add)) at (prev + 0, 61) to (start + 2, 10)
+- Code(Expression(140, Add)) at (prev + 0, 61) to (start + 2, 10)
     = ((c5 + c6) + c7)
 - Code(Counter(8)) at (prev + 2, 10) to (start + 0, 11)
-- Code(Expression(132, Add)) at (prev + 1, 9) to (start + 0, 23)
+- Code(Expression(139, Add)) at (prev + 1, 9) to (start + 0, 23)
     = (((c5 + c6) + c7) + c8)
 - Code(Counter(9)) at (prev + 2, 9) to (start + 0, 15)
-- Code(Expression(130, Add)) at (prev + 2, 1) to (start + 0, 2)
-    = ((c4 + (((c5 + c6) + c7) + c8)) + ((((c9 + c10) + c11) + c12) + (((c1 + Zero) - c2) - c3)))
+- Code(Expression(137, Add)) at (prev + 2, 1) to (start + 0, 2)
+    = ((c4 + (((c5 + c6) + c7) + c8)) + ((((c9 + c10) + c11) + c12) + ((c0 - c2) - c3)))
 
diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map
index 255708d..6ead788 100644
--- a/tests/coverage/coroutine.cov-map
+++ b/tests/coverage/coroutine.cov-map
@@ -1,17 +1,15 @@
 Function name: coroutine::get_u32
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 0b, 01, 01, 0b, 05, 02, 09, 00, 0e, 02, 02, 09, 00, 28, 07, 02, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 0b, 01, 01, 0b, 05, 02, 09, 00, 0e, 02, 02, 09, 00, 28, 01, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 11, 1) to (start + 1, 11)
 - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 14)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 40)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2)
 
 Function name: coroutine::main
 Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 13, 01, 02, 16, 01, 07, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02]
diff --git a/tests/coverage/dead_code.cov-map b/tests/coverage/dead_code.cov-map
index 0b8a40a..31599d9 100644
--- a/tests/coverage/dead_code.cov-map
+++ b/tests/coverage/dead_code.cov-map
@@ -1,17 +1,15 @@
 Function name: dead_code::main
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 1b, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 1b, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 27, 1) to (start + 7, 15)
 - Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: dead_code::unused_fn (unused)
 Raw bytes (24): 0x[01, 01, 00, 04, 00, 0f, 01, 07, 0f, 00, 07, 10, 02, 06, 00, 02, 06, 00, 07, 00, 01, 01, 00, 02]
diff --git a/tests/coverage/drop_trait.cov-map b/tests/coverage/drop_trait.cov-map
index 203d104..eb9d7d7 100644
--- a/tests/coverage/drop_trait.cov-map
+++ b/tests/coverage/drop_trait.cov-map
@@ -7,15 +7,13 @@
 - Code(Counter(0)) at (prev + 9, 5) to (start + 2, 6)
 
 Function name: drop_trait::main
-Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 0e, 01, 05, 0c, 05, 06, 09, 01, 16, 00, 02, 06, 04, 0b, 03, 05, 01, 00, 02]
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 0e, 01, 05, 0c, 05, 06, 09, 01, 16, 00, 02, 06, 04, 0b, 01, 05, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 1
-- expression 0 operands: lhs = Counter(1), rhs = Zero
+Number of expressions: 0
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 14, 1) to (start + 5, 12)
 - Code(Counter(1)) at (prev + 6, 9) to (start + 1, 22)
 - Code(Zero) at (prev + 2, 6) to (start + 4, 11)
-- Code(Expression(0, Add)) at (prev + 5, 1) to (start + 0, 2)
-    = (c1 + Zero)
+- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/fn_sig_into_try.cov-map b/tests/coverage/fn_sig_into_try.cov-map
index c3969f8..4975895 100644
--- a/tests/coverage/fn_sig_into_try.cov-map
+++ b/tests/coverage/fn_sig_into_try.cov-map
@@ -7,47 +7,41 @@
 - Code(Counter(0)) at (prev + 10, 1) to (start + 5, 2)
 
 Function name: fn_sig_into_try::b
-Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 11, 01, 03, 0f, 00, 03, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 00, 04, 01, 11, 01, 03, 0f, 00, 03, 0f, 00, 10, 02, 01, 05, 00, 0c, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Zero
-- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 17, 1) to (start + 3, 15)
 - Code(Zero) at (prev + 3, 15) to (start + 0, 16)
 - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12)
     = (c0 - Zero)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (Zero + (c0 - Zero))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: fn_sig_into_try::c
-Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 18, 01, 03, 17, 00, 03, 17, 00, 18, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 00, 04, 01, 18, 01, 03, 17, 00, 03, 17, 00, 18, 02, 01, 05, 00, 0c, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Zero
-- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 24, 1) to (start + 3, 23)
 - Code(Zero) at (prev + 3, 23) to (start + 0, 24)
 - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12)
     = (c0 - Zero)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (Zero + (c0 - Zero))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: fn_sig_into_try::d
-Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 1f, 01, 04, 0f, 00, 04, 0f, 00, 10, 02, 01, 05, 00, 0c, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 00, 04, 01, 1f, 01, 04, 0f, 00, 04, 0f, 00, 10, 02, 01, 05, 00, 0c, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Zero
-- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 31, 1) to (start + 4, 15)
 - Code(Zero) at (prev + 4, 15) to (start + 0, 16)
 - Code(Expression(0, Sub)) at (prev + 1, 5) to (start + 0, 12)
     = (c0 - Zero)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (Zero + (c0 - Zero))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/generics.cov-map b/tests/coverage/generics.cov-map
index 6079a43..48e191c 100644
--- a/tests/coverage/generics.cov-map
+++ b/tests/coverage/generics.cov-map
@@ -31,15 +31,13 @@
 - Code(Counter(0)) at (prev + 10, 5) to (start + 2, 6)
 
 Function name: generics::main
-Raw bytes (26): 0x[01, 01, 01, 05, 00, 04, 01, 16, 01, 08, 0c, 05, 09, 09, 01, 16, 00, 02, 06, 04, 0b, 03, 05, 01, 00, 02]
+Raw bytes (24): 0x[01, 01, 00, 04, 01, 16, 01, 08, 0c, 05, 09, 09, 01, 16, 00, 02, 06, 04, 0b, 01, 05, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 1
-- expression 0 operands: lhs = Counter(1), rhs = Zero
+Number of expressions: 0
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 22, 1) to (start + 8, 12)
 - Code(Counter(1)) at (prev + 9, 9) to (start + 1, 22)
 - Code(Zero) at (prev + 2, 6) to (start + 4, 11)
-- Code(Expression(0, Add)) at (prev + 5, 1) to (start + 0, 2)
-    = (c1 + Zero)
+- Code(Counter(0)) at (prev + 5, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/if.cov-map b/tests/coverage/if.cov-map
index d7122f4..2b5ae97 100644
--- a/tests/coverage/if.cov-map
+++ b/tests/coverage/if.cov-map
@@ -1,15 +1,13 @@
 Function name: if::main
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 04, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 06, 00, 07, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 04, 01, 12, 10, 05, 13, 05, 05, 06, 02, 05, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 4, 1) to (start + 18, 16)
 - Code(Counter(1)) at (prev + 19, 5) to (start + 5, 6)
 - Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/if_else.cov-map b/tests/coverage/if_else.cov-map
index 7163681..c211191 100644
--- a/tests/coverage/if_else.cov-map
+++ b/tests/coverage/if_else.cov-map
@@ -1,25 +1,18 @@
 Function name: if_else::main
-Raw bytes (53): 0x[01, 01, 07, 01, 05, 05, 02, 1b, 09, 05, 02, 09, 16, 1b, 09, 05, 02, 07, 01, 04, 01, 08, 10, 05, 09, 05, 05, 06, 02, 08, 09, 02, 10, 1b, 06, 09, 00, 10, 09, 01, 05, 05, 06, 16, 07, 05, 05, 06, 13, 06, 01, 00, 02]
+Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 04, 01, 08, 10, 05, 09, 05, 05, 06, 02, 08, 09, 02, 10, 01, 06, 09, 00, 10, 09, 01, 05, 05, 06, 06, 07, 05, 05, 06, 01, 06, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 7
+Number of expressions: 2
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Expression(6, Add), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 4 operands: lhs = Counter(2), rhs = Expression(5, Sub)
-- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(2)
-- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 7
 - Code(Counter(0)) at (prev + 4, 1) to (start + 8, 16)
 - Code(Counter(1)) at (prev + 9, 5) to (start + 5, 6)
 - Code(Expression(0, Sub)) at (prev + 8, 9) to (start + 2, 16)
     = (c0 - c1)
-- Code(Expression(6, Add)) at (prev + 6, 9) to (start + 0, 16)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 6, 9) to (start + 0, 16)
 - Code(Counter(2)) at (prev + 1, 5) to (start + 5, 6)
-- Code(Expression(5, Sub)) at (prev + 7, 5) to (start + 5, 6)
-    = ((c1 + (c0 - c1)) - c2)
-- Code(Expression(4, Add)) at (prev + 6, 1) to (start + 0, 2)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
+- Code(Expression(1, Sub)) at (prev + 7, 5) to (start + 5, 6)
+    = (c0 - c2)
+- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/if_not.cov-map b/tests/coverage/if_not.cov-map
index 3c66055..9e11ed7 100644
--- a/tests/coverage/if_not.cov-map
+++ b/tests/coverage/if_not.cov-map
@@ -1,39 +1,23 @@
 Function name: if_not::if_not
-Raw bytes (86): 0x[01, 01, 10, 01, 05, 05, 02, 3f, 09, 05, 02, 09, 3a, 3f, 09, 05, 02, 37, 0d, 09, 3a, 3f, 09, 05, 02, 0d, 32, 37, 0d, 09, 3a, 3f, 09, 05, 02, 0a, 01, 05, 01, 03, 0d, 02, 04, 05, 02, 06, 05, 02, 06, 00, 07, 3f, 03, 09, 01, 0d, 3a, 02, 05, 02, 06, 09, 02, 06, 00, 07, 37, 03, 09, 01, 0d, 32, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 2f, 03, 01, 00, 02]
+Raw bytes (60): 0x[01, 01, 03, 01, 05, 01, 09, 01, 0d, 0a, 01, 05, 01, 03, 0d, 02, 04, 05, 02, 06, 05, 02, 06, 00, 07, 01, 03, 09, 01, 0d, 06, 02, 05, 02, 06, 09, 02, 06, 00, 07, 01, 03, 09, 01, 0d, 0a, 02, 05, 02, 06, 0d, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 16
+Number of expressions: 3
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Expression(15, Add), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 4 operands: lhs = Counter(2), rhs = Expression(14, Sub)
-- expression 5 operands: lhs = Expression(15, Add), rhs = Counter(2)
-- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 7 operands: lhs = Expression(13, Add), rhs = Counter(3)
-- expression 8 operands: lhs = Counter(2), rhs = Expression(14, Sub)
-- expression 9 operands: lhs = Expression(15, Add), rhs = Counter(2)
-- expression 10 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 11 operands: lhs = Counter(3), rhs = Expression(12, Sub)
-- expression 12 operands: lhs = Expression(13, Add), rhs = Counter(3)
-- expression 13 operands: lhs = Counter(2), rhs = Expression(14, Sub)
-- expression 14 operands: lhs = Expression(15, Add), rhs = Counter(2)
-- expression 15 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(3)
 Number of file 0 mappings: 10
 - Code(Counter(0)) at (prev + 5, 1) to (start + 3, 13)
 - Code(Expression(0, Sub)) at (prev + 4, 5) to (start + 2, 6)
     = (c0 - c1)
 - Code(Counter(1)) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(15, Add)) at (prev + 3, 9) to (start + 1, 13)
-    = (c1 + (c0 - c1))
-- Code(Expression(14, Sub)) at (prev + 2, 5) to (start + 2, 6)
-    = ((c1 + (c0 - c1)) - c2)
+- Code(Counter(0)) at (prev + 3, 9) to (start + 1, 13)
+- Code(Expression(1, Sub)) at (prev + 2, 5) to (start + 2, 6)
+    = (c0 - c2)
 - Code(Counter(2)) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(13, Add)) at (prev + 3, 9) to (start + 1, 13)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
-- Code(Expression(12, Sub)) at (prev + 2, 5) to (start + 2, 6)
-    = ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)
+- Code(Counter(0)) at (prev + 3, 9) to (start + 1, 13)
+- Code(Expression(2, Sub)) at (prev + 2, 5) to (start + 2, 6)
+    = (c0 - c3)
 - Code(Counter(3)) at (prev + 2, 12) to (start + 2, 6)
-- Code(Expression(11, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/inline-dead.cov-map b/tests/coverage/inline-dead.cov-map
index f77781c..96b907c 100644
--- a/tests/coverage/inline-dead.cov-map
+++ b/tests/coverage/inline-dead.cov-map
@@ -7,19 +7,17 @@
 - Code(Zero) at (prev + 23, 1) to (start + 2, 2)
 
 Function name: inline_dead::live::<false>
-Raw bytes (28): 0x[01, 01, 02, 01, 00, 00, 02, 04, 01, 0e, 01, 01, 09, 00, 02, 09, 00, 0f, 02, 02, 09, 00, 0a, 07, 02, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 00, 04, 01, 0e, 01, 01, 09, 00, 02, 09, 00, 0f, 02, 02, 09, 00, 0a, 01, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Zero
-- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 14, 1) to (start + 1, 9)
 - Code(Zero) at (prev + 2, 9) to (start + 0, 15)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 10)
     = (c0 - Zero)
-- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2)
-    = (Zero + (c0 - Zero))
+- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2)
 
 Function name: inline_dead::main
 Raw bytes (14): 0x[01, 01, 00, 02, 01, 04, 01, 03, 0a, 01, 06, 05, 01, 02]
diff --git a/tests/coverage/inline.cov-map b/tests/coverage/inline.cov-map
index 001c333..2366a3b 100644
--- a/tests/coverage/inline.cov-map
+++ b/tests/coverage/inline.cov-map
@@ -1,18 +1,16 @@
 Function name: inline::display::<char>
-Raw bytes (33): 0x[01, 01, 02, 01, 05, 03, 05, 05, 01, 29, 01, 00, 22, 05, 01, 09, 00, 0a, 03, 00, 0e, 00, 10, 05, 00, 11, 02, 06, 06, 03, 05, 01, 02]
+Raw bytes (31): 0x[01, 01, 01, 01, 05, 05, 01, 29, 01, 00, 22, 05, 01, 09, 00, 0a, 03, 00, 0e, 00, 10, 05, 00, 11, 02, 06, 01, 03, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(1)
 Number of file 0 mappings: 5
 - Code(Counter(0)) at (prev + 41, 1) to (start + 0, 34)
 - Code(Counter(1)) at (prev + 1, 9) to (start + 0, 10)
 - Code(Expression(0, Add)) at (prev + 0, 14) to (start + 0, 16)
     = (c0 + c1)
 - Code(Counter(1)) at (prev + 0, 17) to (start + 2, 6)
-- Code(Expression(1, Sub)) at (prev + 3, 5) to (start + 1, 2)
-    = ((c0 + c1) - c1)
+- Code(Counter(0)) at (prev + 3, 5) to (start + 1, 2)
 
 Function name: inline::error
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 31, 01, 01, 14]
diff --git a/tests/coverage/inner_items.cov-map b/tests/coverage/inner_items.cov-map
index 3f39d74..6ccc3f0 100644
--- a/tests/coverage/inner_items.cov-map
+++ b/tests/coverage/inner_items.cov-map
@@ -15,29 +15,22 @@
 - Code(Counter(0)) at (prev + 40, 9) to (start + 3, 10)
 
 Function name: inner_items::main
-Raw bytes (53): 0x[01, 01, 07, 01, 05, 05, 02, 1b, 09, 05, 02, 09, 16, 1b, 09, 05, 02, 07, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 1b, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 16, 02, 06, 00, 07, 13, 02, 09, 05, 02]
+Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 03, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 01, 24, 08, 00, 0f, 09, 00, 10, 02, 06, 06, 02, 06, 00, 07, 01, 02, 09, 05, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 7
+Number of expressions: 2
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Expression(6, Add), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 4 operands: lhs = Counter(2), rhs = Expression(5, Sub)
-- expression 5 operands: lhs = Expression(6, Add), rhs = Counter(2)
-- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 7
 - Code(Counter(0)) at (prev + 3, 1) to (start + 7, 15)
 - Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(6, Add)) at (prev + 36, 8) to (start + 0, 15)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 36, 8) to (start + 0, 15)
 - Code(Counter(2)) at (prev + 0, 16) to (start + 2, 6)
-- Code(Expression(5, Sub)) at (prev + 2, 6) to (start + 0, 7)
-    = ((c1 + (c0 - c1)) - c2)
-- Code(Expression(4, Add)) at (prev + 2, 9) to (start + 5, 2)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
+- Code(Expression(1, Sub)) at (prev + 2, 6) to (start + 0, 7)
+    = (c0 - c2)
+- Code(Counter(0)) at (prev + 2, 9) to (start + 5, 2)
 
 Function name: inner_items::main::in_func
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 12, 05, 04, 06]
diff --git a/tests/coverage/issue-84561.cov-map b/tests/coverage/issue-84561.cov-map
index ab66a2f..c4087d9 100644
--- a/tests/coverage/issue-84561.cov-map
+++ b/tests/coverage/issue-84561.cov-map
@@ -1,17 +1,15 @@
 Function name: <issue_84561::Foo as core::fmt::Debug>::fmt
-Raw bytes (29): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 8a, 01, 05, 01, 25, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 07, 01, 05, 00, 06]
+Raw bytes (27): 0x[01, 01, 01, 01, 05, 04, 01, 8a, 01, 05, 01, 25, 05, 01, 25, 00, 26, 02, 01, 09, 00, 0f, 01, 01, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 138, 5) to (start + 1, 37)
 - Code(Counter(1)) at (prev + 1, 37) to (start + 0, 38)
 - Code(Expression(0, Sub)) at (prev + 1, 9) to (start + 0, 15)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 0, 6)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 6)
 
 Function name: issue_84561::main
 Raw bytes (10): 0x[01, 01, 00, 01, 01, b4, 01, 01, 04, 02]
@@ -22,51 +20,30 @@
 - Code(Counter(0)) at (prev + 180, 1) to (start + 4, 2)
 
 Function name: issue_84561::test1
-Raw bytes (78): 0x[01, 01, 0e, 05, 06, 01, 05, 09, 36, 03, 09, 0d, 2e, 33, 0d, 09, 36, 03, 09, 11, 26, 2b, 11, 0d, 2e, 33, 0d, 09, 36, 03, 09, 09, 01, 9a, 01, 01, 01, 0b, 05, 01, 0c, 00, 1e, 03, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 33, 01, 0d, 01, 0b, 0d, 01, 0c, 00, 1e, 2b, 01, 05, 03, 0b, 11, 03, 0c, 00, 1e, 23, 01, 01, 00, 02]
+Raw bytes (50): 0x[01, 01, 00, 09, 01, 9a, 01, 01, 01, 0b, 05, 01, 0c, 00, 1e, 01, 01, 05, 00, 0b, 09, 00, 0c, 00, 1e, 01, 01, 0d, 01, 0b, 0d, 01, 0c, 00, 1e, 01, 01, 05, 03, 0b, 11, 03, 0c, 00, 1e, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 14
-- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Sub)
-- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 2 operands: lhs = Counter(2), rhs = Expression(13, Sub)
-- expression 3 operands: lhs = Expression(0, Add), rhs = Counter(2)
-- expression 4 operands: lhs = Counter(3), rhs = Expression(11, Sub)
-- expression 5 operands: lhs = Expression(12, Add), rhs = Counter(3)
-- expression 6 operands: lhs = Counter(2), rhs = Expression(13, Sub)
-- expression 7 operands: lhs = Expression(0, Add), rhs = Counter(2)
-- expression 8 operands: lhs = Counter(4), rhs = Expression(9, Sub)
-- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(4)
-- expression 10 operands: lhs = Counter(3), rhs = Expression(11, Sub)
-- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(3)
-- expression 12 operands: lhs = Counter(2), rhs = Expression(13, Sub)
-- expression 13 operands: lhs = Expression(0, Add), rhs = Counter(2)
+Number of expressions: 0
 Number of file 0 mappings: 9
 - Code(Counter(0)) at (prev + 154, 1) to (start + 1, 11)
 - Code(Counter(1)) at (prev + 1, 12) to (start + 0, 30)
-- Code(Expression(0, Add)) at (prev + 1, 5) to (start + 0, 11)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 0, 11)
 - Code(Counter(2)) at (prev + 0, 12) to (start + 0, 30)
-- Code(Expression(12, Add)) at (prev + 1, 13) to (start + 1, 11)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
+- Code(Counter(0)) at (prev + 1, 13) to (start + 1, 11)
 - Code(Counter(3)) at (prev + 1, 12) to (start + 0, 30)
-- Code(Expression(10, Add)) at (prev + 1, 5) to (start + 3, 11)
-    = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 3, 11)
 - Code(Counter(4)) at (prev + 3, 12) to (start + 0, 30)
-- Code(Expression(8, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: issue_84561::test2
-Raw bytes (24): 0x[01, 01, 02, 05, 06, 01, 05, 03, 01, b0, 01, 01, 01, 10, 05, 01, 11, 00, 23, 03, 01, 01, 00, 02]
+Raw bytes (20): 0x[01, 01, 00, 03, 01, b0, 01, 01, 01, 10, 05, 01, 11, 00, 23, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
-- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Sub)
-- expression 1 operands: lhs = Counter(0), rhs = Counter(1)
+Number of expressions: 0
 Number of file 0 mappings: 3
 - Code(Counter(0)) at (prev + 176, 1) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 1, 17) to (start + 0, 35)
-- Code(Expression(0, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: issue_84561::test2::call_print
 Raw bytes (10): 0x[01, 01, 00, 01, 01, a7, 01, 09, 02, 0a]
@@ -77,10 +54,10 @@
 - Code(Counter(0)) at (prev + 167, 9) to (start + 2, 10)
 
 Function name: issue_84561::test3
-Raw bytes (436): 0x[01, 01, 41, 05, 00, 0d, 00, 15, 00, 12, 00, 15, 00, 21, 00, 1e, 00, 21, 00, 31, 00, 3d, 00, 2e, 45, 3d, 00, 42, 49, 45, 00, 3f, 51, 42, 49, 45, 00, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 92, 01, 55, 51, 00, 8f, 01, 5d, 92, 01, 55, 51, 00, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 82, 01, 65, 87, 01, 61, 5d, 8a, 01, 8f, 01, 5d, 92, 01, 55, 51, 00, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, 00, fe, 01, 82, 02, 00, 69, 6d, 69, 6d, 82, 02, 00, 69, 6d, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, ee, 01, 00, f3, 01, 7d, 75, f6, 01, fb, 01, 79, 00, fe, 01, 82, 02, 00, 69, 6d, 33, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 87, 01, 03, 05, 00, 0f, 8f, 01, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 8a, 01, 02, 0d, 00, 13, 82, 01, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 7e, 02, 0d, 00, 13, f3, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, fb, 01, 02, 0d, 00, 17, 82, 02, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, fe, 01, 02, 15, 00, 1b, f6, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, ee, 01, 02, 05, 00, 0f, ea, 01, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02]
+Raw bytes (375): 0x[01, 01, 31, 05, 00, 0d, 00, 15, 00, 12, 00, 15, 00, 21, 00, 1e, 00, 21, 00, 31, 00, 3d, 00, 2e, 45, 3d, 00, 42, 49, 45, 00, 3f, 51, 42, 49, 45, 00, 7a, 55, 51, 00, 7a, 55, 51, 00, 77, 5d, 7a, 55, 51, 00, 77, 61, 7a, 55, 51, 00, 72, 65, 77, 61, 7a, 55, 51, 00, 75, be, 01, c2, 01, 79, 69, 6d, 69, 6d, 69, 6d, c2, 01, 00, 69, 6d, c2, 01, 79, 69, 6d, bb, 01, 7d, 75, be, 01, c2, 01, 79, 69, 6d, b6, 01, 00, bb, 01, 7d, 75, be, 01, c2, 01, 79, 69, 6d, 33, 01, 08, 01, 03, 1c, 05, 04, 09, 01, 1c, 02, 02, 05, 04, 1f, 0d, 05, 05, 00, 1f, 06, 01, 05, 00, 1f, 15, 01, 09, 01, 1c, 12, 02, 05, 00, 1f, 0e, 01, 05, 00, 0f, 00, 00, 20, 00, 30, 21, 01, 05, 03, 0f, 00, 03, 20, 00, 30, 00, 00, 33, 00, 41, 00, 00, 4b, 00, 5a, 1e, 01, 05, 00, 0f, 00, 05, 09, 03, 10, 00, 05, 0d, 00, 1b, 00, 02, 0d, 00, 1c, 1a, 04, 09, 05, 06, 31, 06, 05, 03, 06, 22, 04, 05, 03, 06, 3d, 04, 09, 04, 06, 2e, 05, 08, 00, 0f, 45, 01, 09, 03, 0a, 2a, 05, 09, 03, 0a, 3f, 05, 08, 00, 0f, 51, 01, 09, 00, 13, 00, 03, 0d, 00, 1d, 3a, 03, 09, 00, 13, 00, 03, 0d, 00, 1d, 77, 03, 05, 00, 0f, 77, 01, 0c, 00, 13, 5d, 01, 0d, 00, 13, 56, 02, 0d, 00, 13, 72, 04, 05, 02, 13, 65, 03, 0d, 00, 13, 6e, 02, 0d, 00, 13, bb, 01, 03, 05, 00, 0f, 69, 01, 0c, 00, 13, 6d, 01, 0d, 03, 0e, 75, 04, 0d, 00, 13, c2, 01, 02, 0d, 00, 17, c2, 01, 01, 14, 00, 1b, 00, 01, 15, 00, 1b, 92, 01, 02, 15, 00, 1b, be, 01, 04, 0d, 00, 13, 7d, 03, 09, 00, 19, b6, 01, 02, 05, 00, 0f, b2, 01, 03, 09, 00, 22, 00, 02, 05, 00, 0f, 00, 03, 09, 00, 2c, 00, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 65
+Number of expressions: 49
 - expression 0 operands: lhs = Counter(1), rhs = Zero
 - expression 1 operands: lhs = Counter(3), rhs = Zero
 - expression 2 operands: lhs = Counter(5), rhs = Zero
@@ -98,54 +75,38 @@
 - expression 14 operands: lhs = Expression(15, Add), rhs = Counter(20)
 - expression 15 operands: lhs = Expression(16, Sub), rhs = Counter(18)
 - expression 16 operands: lhs = Counter(17), rhs = Zero
-- expression 17 operands: lhs = Counter(23), rhs = Expression(34, Sub)
-- expression 18 operands: lhs = Expression(35, Add), rhs = Counter(23)
-- expression 19 operands: lhs = Expression(36, Sub), rhs = Counter(21)
+- expression 17 operands: lhs = Expression(30, Sub), rhs = Counter(21)
+- expression 18 operands: lhs = Counter(20), rhs = Zero
+- expression 19 operands: lhs = Expression(30, Sub), rhs = Counter(21)
 - expression 20 operands: lhs = Counter(20), rhs = Zero
-- expression 21 operands: lhs = Expression(36, Sub), rhs = Counter(21)
-- expression 22 operands: lhs = Counter(20), rhs = Zero
-- expression 23 operands: lhs = Expression(35, Add), rhs = Counter(23)
-- expression 24 operands: lhs = Expression(36, Sub), rhs = Counter(21)
-- expression 25 operands: lhs = Counter(20), rhs = Zero
-- expression 26 operands: lhs = Expression(33, Add), rhs = Counter(24)
-- expression 27 operands: lhs = Counter(23), rhs = Expression(34, Sub)
-- expression 28 operands: lhs = Expression(35, Add), rhs = Counter(23)
-- expression 29 operands: lhs = Expression(36, Sub), rhs = Counter(21)
+- expression 21 operands: lhs = Expression(29, Add), rhs = Counter(23)
+- expression 22 operands: lhs = Expression(30, Sub), rhs = Counter(21)
+- expression 23 operands: lhs = Counter(20), rhs = Zero
+- expression 24 operands: lhs = Expression(29, Add), rhs = Counter(24)
+- expression 25 operands: lhs = Expression(30, Sub), rhs = Counter(21)
+- expression 26 operands: lhs = Counter(20), rhs = Zero
+- expression 27 operands: lhs = Expression(28, Sub), rhs = Counter(25)
+- expression 28 operands: lhs = Expression(29, Add), rhs = Counter(24)
+- expression 29 operands: lhs = Expression(30, Sub), rhs = Counter(21)
 - expression 30 operands: lhs = Counter(20), rhs = Zero
-- expression 31 operands: lhs = Expression(32, Sub), rhs = Counter(25)
-- expression 32 operands: lhs = Expression(33, Add), rhs = Counter(24)
-- expression 33 operands: lhs = Counter(23), rhs = Expression(34, Sub)
-- expression 34 operands: lhs = Expression(35, Add), rhs = Counter(23)
-- expression 35 operands: lhs = Expression(36, Sub), rhs = Counter(21)
-- expression 36 operands: lhs = Counter(20), rhs = Zero
-- expression 37 operands: lhs = Counter(29), rhs = Expression(61, Sub)
-- expression 38 operands: lhs = Expression(62, Add), rhs = Counter(30)
-- expression 39 operands: lhs = Zero, rhs = Expression(63, Sub)
-- expression 40 operands: lhs = Expression(64, Sub), rhs = Zero
-- expression 41 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 42 operands: lhs = Zero, rhs = Expression(63, Sub)
-- expression 43 operands: lhs = Expression(64, Sub), rhs = Zero
-- expression 44 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 45 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 46 operands: lhs = Expression(64, Sub), rhs = Zero
-- expression 47 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 48 operands: lhs = Expression(62, Add), rhs = Counter(30)
-- expression 49 operands: lhs = Zero, rhs = Expression(63, Sub)
-- expression 50 operands: lhs = Expression(64, Sub), rhs = Zero
-- expression 51 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 52 operands: lhs = Expression(60, Add), rhs = Counter(31)
-- expression 53 operands: lhs = Counter(29), rhs = Expression(61, Sub)
-- expression 54 operands: lhs = Expression(62, Add), rhs = Counter(30)
-- expression 55 operands: lhs = Zero, rhs = Expression(63, Sub)
-- expression 56 operands: lhs = Expression(64, Sub), rhs = Zero
-- expression 57 operands: lhs = Counter(26), rhs = Counter(27)
-- expression 58 operands: lhs = Expression(59, Sub), rhs = Zero
-- expression 59 operands: lhs = Expression(60, Add), rhs = Counter(31)
-- expression 60 operands: lhs = Counter(29), rhs = Expression(61, Sub)
-- expression 61 operands: lhs = Expression(62, Add), rhs = Counter(30)
-- expression 62 operands: lhs = Zero, rhs = Expression(63, Sub)
-- expression 63 operands: lhs = Expression(64, Sub), rhs = Zero
-- expression 64 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 31 operands: lhs = Counter(29), rhs = Expression(47, Sub)
+- expression 32 operands: lhs = Expression(48, Sub), rhs = Counter(30)
+- expression 33 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 34 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 35 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 36 operands: lhs = Expression(48, Sub), rhs = Zero
+- expression 37 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 38 operands: lhs = Expression(48, Sub), rhs = Counter(30)
+- expression 39 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 40 operands: lhs = Expression(46, Add), rhs = Counter(31)
+- expression 41 operands: lhs = Counter(29), rhs = Expression(47, Sub)
+- expression 42 operands: lhs = Expression(48, Sub), rhs = Counter(30)
+- expression 43 operands: lhs = Counter(26), rhs = Counter(27)
+- expression 44 operands: lhs = Expression(45, Sub), rhs = Zero
+- expression 45 operands: lhs = Expression(46, Add), rhs = Counter(31)
+- expression 46 operands: lhs = Counter(29), rhs = Expression(47, Sub)
+- expression 47 operands: lhs = Expression(48, Sub), rhs = Counter(30)
+- expression 48 operands: lhs = Counter(26), rhs = Counter(27)
 Number of file 0 mappings: 51
 - Code(Counter(0)) at (prev + 8, 1) to (start + 3, 28)
 - Code(Counter(1)) at (prev + 4, 9) to (start + 1, 28)
@@ -187,37 +148,37 @@
 - Code(Expression(14, Sub)) at (prev + 3, 9) to (start + 0, 19)
     = (((c17 - Zero) + c18) - c20)
 - Code(Zero) at (prev + 3, 13) to (start + 0, 29)
-- Code(Expression(33, Add)) at (prev + 3, 5) to (start + 0, 15)
-    = (c23 + (((c20 - Zero) + c21) - c23))
-- Code(Expression(35, Add)) at (prev + 1, 12) to (start + 0, 19)
+- Code(Expression(29, Add)) at (prev + 3, 5) to (start + 0, 15)
+    = ((c20 - Zero) + c21)
+- Code(Expression(29, Add)) at (prev + 1, 12) to (start + 0, 19)
     = ((c20 - Zero) + c21)
 - Code(Counter(23)) at (prev + 1, 13) to (start + 0, 19)
-- Code(Expression(34, Sub)) at (prev + 2, 13) to (start + 0, 19)
+- Code(Expression(21, Sub)) at (prev + 2, 13) to (start + 0, 19)
     = (((c20 - Zero) + c21) - c23)
-- Code(Expression(32, Sub)) at (prev + 4, 5) to (start + 2, 19)
-    = ((c23 + (((c20 - Zero) + c21) - c23)) - c24)
+- Code(Expression(28, Sub)) at (prev + 4, 5) to (start + 2, 19)
+    = (((c20 - Zero) + c21) - c24)
 - Code(Counter(25)) at (prev + 3, 13) to (start + 0, 19)
-- Code(Expression(31, Sub)) at (prev + 2, 13) to (start + 0, 19)
-    = (((c23 + (((c20 - Zero) + c21) - c23)) - c24) - c25)
-- Code(Expression(60, Add)) at (prev + 3, 5) to (start + 0, 15)
-    = (c29 + ((Zero + ((c26 - c27) - Zero)) - c30))
+- Code(Expression(27, Sub)) at (prev + 2, 13) to (start + 0, 19)
+    = ((((c20 - Zero) + c21) - c24) - c25)
+- Code(Expression(46, Add)) at (prev + 3, 5) to (start + 0, 15)
+    = (c29 + ((c26 - c27) - c30))
 - Code(Counter(26)) at (prev + 1, 12) to (start + 0, 19)
 - Code(Counter(27)) at (prev + 1, 13) to (start + 3, 14)
 - Code(Counter(29)) at (prev + 4, 13) to (start + 0, 19)
-- Code(Expression(62, Add)) at (prev + 2, 13) to (start + 0, 23)
-    = (Zero + ((c26 - c27) - Zero))
-- Code(Expression(64, Sub)) at (prev + 1, 20) to (start + 0, 27)
+- Code(Expression(48, Sub)) at (prev + 2, 13) to (start + 0, 23)
+    = (c26 - c27)
+- Code(Expression(48, Sub)) at (prev + 1, 20) to (start + 0, 27)
     = (c26 - c27)
 - Code(Zero) at (prev + 1, 21) to (start + 0, 27)
-- Code(Expression(63, Sub)) at (prev + 2, 21) to (start + 0, 27)
+- Code(Expression(36, Sub)) at (prev + 2, 21) to (start + 0, 27)
     = ((c26 - c27) - Zero)
-- Code(Expression(61, Sub)) at (prev + 4, 13) to (start + 0, 19)
-    = ((Zero + ((c26 - c27) - Zero)) - c30)
+- Code(Expression(47, Sub)) at (prev + 4, 13) to (start + 0, 19)
+    = ((c26 - c27) - c30)
 - Code(Counter(31)) at (prev + 3, 9) to (start + 0, 25)
-- Code(Expression(59, Sub)) at (prev + 2, 5) to (start + 0, 15)
-    = ((c29 + ((Zero + ((c26 - c27) - Zero)) - c30)) - c31)
-- Code(Expression(58, Sub)) at (prev + 3, 9) to (start + 0, 34)
-    = (((c29 + ((Zero + ((c26 - c27) - Zero)) - c30)) - c31) - Zero)
+- Code(Expression(45, Sub)) at (prev + 2, 5) to (start + 0, 15)
+    = ((c29 + ((c26 - c27) - c30)) - c31)
+- Code(Expression(44, Sub)) at (prev + 3, 9) to (start + 0, 34)
+    = (((c29 + ((c26 - c27) - c30)) - c31) - Zero)
 - Code(Zero) at (prev + 2, 5) to (start + 0, 15)
 - Code(Zero) at (prev + 3, 9) to (start + 0, 44)
 - Code(Zero) at (prev + 2, 1) to (start + 0, 2)
diff --git a/tests/coverage/lazy_boolean.cov-map b/tests/coverage/lazy_boolean.cov-map
index 03dbb59..8dca205 100644
--- a/tests/coverage/lazy_boolean.cov-map
+++ b/tests/coverage/lazy_boolean.cov-map
@@ -1,219 +1,49 @@
 Function name: lazy_boolean::main
-Raw bytes (636): 0x[01, 01, a4, 01, 01, 05, 09, 8a, 05, 8f, 05, 09, 05, 02, 05, 02, 8f, 05, 09, 05, 02, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 09, 8a, 05, 8f, 05, 09, 05, 02, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, d7, 04, 25, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 25, d2, 04, d7, 04, 25, 21, da, 04, df, 04, 21, 1d, e2, 04, e7, 04, 1d, 19, ea, 04, ef, 04, 19, 15, f2, 04, f7, 04, 15, 11, fa, 04, ff, 04, 11, 0d, 82, 05, 87, 05, 0d, 09, 8a, 05, 8f, 05, 09, 05, 02, 1c, 01, 04, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 06, 00, 07, 87, 05, 02, 09, 00, 11, 8f, 05, 02, 0d, 00, 12, 8a, 05, 02, 0d, 00, 12, ff, 04, 03, 09, 00, 11, 87, 05, 02, 0d, 00, 12, 82, 05, 02, 0d, 00, 12, f7, 04, 02, 09, 00, 11, ff, 04, 00, 14, 00, 19, 11, 00, 1d, 00, 22, ef, 04, 01, 09, 00, 11, f7, 04, 00, 14, 00, 19, 15, 00, 1d, 00, 22, ef, 04, 03, 09, 01, 10, ea, 04, 02, 05, 03, 06, 19, 03, 06, 00, 07, e7, 04, 03, 09, 00, 10, 1d, 01, 05, 03, 06, e2, 04, 05, 05, 03, 06, df, 04, 05, 08, 00, 10, da, 04, 00, 11, 02, 06, 21, 02, 06, 00, 07, d7, 04, 02, 08, 00, 0f, 25, 00, 10, 02, 06, d2, 04, 02, 0c, 02, 06, cf, 04, 03, 01, 00, 02]
+Raw bytes (158): 0x[01, 01, 07, 01, 05, 01, 09, 01, 0d, 01, 19, 01, 1d, 01, 21, 01, 25, 1c, 01, 04, 01, 07, 0f, 05, 07, 10, 04, 06, 02, 04, 06, 00, 07, 01, 02, 09, 00, 11, 01, 02, 0d, 00, 12, 06, 02, 0d, 00, 12, 01, 03, 09, 00, 11, 01, 02, 0d, 00, 12, 0a, 02, 0d, 00, 12, 01, 02, 09, 00, 11, 01, 00, 14, 00, 19, 11, 00, 1d, 00, 22, 01, 01, 09, 00, 11, 01, 00, 14, 00, 19, 15, 00, 1d, 00, 22, 01, 03, 09, 01, 10, 0e, 02, 05, 03, 06, 19, 03, 06, 00, 07, 01, 03, 09, 00, 10, 1d, 01, 05, 03, 06, 12, 05, 05, 03, 06, 01, 05, 08, 00, 10, 16, 00, 11, 02, 06, 21, 02, 06, 00, 07, 01, 02, 08, 00, 0f, 25, 00, 10, 02, 06, 1a, 02, 0c, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 164
+Number of expressions: 7
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 2 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 4 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 5 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 7 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 8 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 9 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 10 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 11 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 12 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 13 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 14 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 15 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 16 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 17 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 18 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 19 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 20 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 21 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 22 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 23 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 24 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 25 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 26 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 27 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 28 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 29 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 30 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 31 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 32 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 33 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 34 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 35 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 36 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 37 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 38 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 39 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 40 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 41 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 42 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 43 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 44 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 45 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 46 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 47 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 48 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 49 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 50 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 51 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 52 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 53 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 54 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 55 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 56 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 57 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 58 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 59 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 60 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 61 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 62 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 63 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 64 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 65 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 66 operands: lhs = Counter(6), rhs = Expression(154, Sub)
-- expression 67 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 68 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 69 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 70 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 71 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 72 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 73 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 74 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 75 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 76 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 77 operands: lhs = Expression(153, Add), rhs = Counter(7)
-- expression 78 operands: lhs = Counter(6), rhs = Expression(154, Sub)
-- expression 79 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 80 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 81 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 82 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 83 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 84 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 85 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 86 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 87 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 88 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 89 operands: lhs = Counter(7), rhs = Expression(152, Sub)
-- expression 90 operands: lhs = Expression(153, Add), rhs = Counter(7)
-- expression 91 operands: lhs = Counter(6), rhs = Expression(154, Sub)
-- expression 92 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 93 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 94 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 95 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 96 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 97 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 98 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 99 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 100 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 101 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 102 operands: lhs = Expression(151, Add), rhs = Counter(8)
-- expression 103 operands: lhs = Counter(7), rhs = Expression(152, Sub)
-- expression 104 operands: lhs = Expression(153, Add), rhs = Counter(7)
-- expression 105 operands: lhs = Counter(6), rhs = Expression(154, Sub)
-- expression 106 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 107 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 108 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 109 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 110 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 111 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 112 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 113 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 114 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 115 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 116 operands: lhs = Counter(8), rhs = Expression(150, Sub)
-- expression 117 operands: lhs = Expression(151, Add), rhs = Counter(8)
-- expression 118 operands: lhs = Counter(7), rhs = Expression(152, Sub)
-- expression 119 operands: lhs = Expression(153, Add), rhs = Counter(7)
-- expression 120 operands: lhs = Counter(6), rhs = Expression(154, Sub)
-- expression 121 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 122 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 123 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 124 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 125 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 126 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 127 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 128 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 129 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 130 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 131 operands: lhs = Expression(149, Add), rhs = Counter(9)
-- expression 132 operands: lhs = Counter(8), rhs = Expression(150, Sub)
-- expression 133 operands: lhs = Expression(151, Add), rhs = Counter(8)
-- expression 134 operands: lhs = Counter(7), rhs = Expression(152, Sub)
-- expression 135 operands: lhs = Expression(153, Add), rhs = Counter(7)
-- expression 136 operands: lhs = Counter(6), rhs = Expression(154, Sub)
-- expression 137 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 138 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 139 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 140 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 141 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 142 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 143 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 144 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 145 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 146 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 147 operands: lhs = Counter(9), rhs = Expression(148, Sub)
-- expression 148 operands: lhs = Expression(149, Add), rhs = Counter(9)
-- expression 149 operands: lhs = Counter(8), rhs = Expression(150, Sub)
-- expression 150 operands: lhs = Expression(151, Add), rhs = Counter(8)
-- expression 151 operands: lhs = Counter(7), rhs = Expression(152, Sub)
-- expression 152 operands: lhs = Expression(153, Add), rhs = Counter(7)
-- expression 153 operands: lhs = Counter(6), rhs = Expression(154, Sub)
-- expression 154 operands: lhs = Expression(155, Add), rhs = Counter(6)
-- expression 155 operands: lhs = Counter(5), rhs = Expression(156, Sub)
-- expression 156 operands: lhs = Expression(157, Add), rhs = Counter(5)
-- expression 157 operands: lhs = Counter(4), rhs = Expression(158, Sub)
-- expression 158 operands: lhs = Expression(159, Add), rhs = Counter(4)
-- expression 159 operands: lhs = Counter(3), rhs = Expression(160, Sub)
-- expression 160 operands: lhs = Expression(161, Add), rhs = Counter(3)
-- expression 161 operands: lhs = Counter(2), rhs = Expression(162, Sub)
-- expression 162 operands: lhs = Expression(163, Add), rhs = Counter(2)
-- expression 163 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(3)
+- expression 3 operands: lhs = Counter(0), rhs = Counter(6)
+- expression 4 operands: lhs = Counter(0), rhs = Counter(7)
+- expression 5 operands: lhs = Counter(0), rhs = Counter(8)
+- expression 6 operands: lhs = Counter(0), rhs = Counter(9)
 Number of file 0 mappings: 28
 - Code(Counter(0)) at (prev + 4, 1) to (start + 7, 15)
 - Code(Counter(1)) at (prev + 7, 16) to (start + 4, 6)
 - Code(Expression(0, Sub)) at (prev + 4, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(161, Add)) at (prev + 2, 9) to (start + 0, 17)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
-- Code(Expression(163, Add)) at (prev + 2, 13) to (start + 0, 18)
-    = (c1 + (c0 - c1))
-- Code(Expression(162, Sub)) at (prev + 2, 13) to (start + 0, 18)
-    = ((c1 + (c0 - c1)) - c2)
-- Code(Expression(159, Add)) at (prev + 3, 9) to (start + 0, 17)
-    = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
-- Code(Expression(161, Add)) at (prev + 2, 13) to (start + 0, 18)
-    = (c2 + ((c1 + (c0 - c1)) - c2))
-- Code(Expression(160, Sub)) at (prev + 2, 13) to (start + 0, 18)
-    = ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)
-- Code(Expression(157, Add)) at (prev + 2, 9) to (start + 0, 17)
-    = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4))
-- Code(Expression(159, Add)) at (prev + 0, 20) to (start + 0, 25)
-    = (c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3))
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 17)
+- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 18)
+- Code(Expression(1, Sub)) at (prev + 2, 13) to (start + 0, 18)
+    = (c0 - c2)
+- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 17)
+- Code(Counter(0)) at (prev + 2, 13) to (start + 0, 18)
+- Code(Expression(2, Sub)) at (prev + 2, 13) to (start + 0, 18)
+    = (c0 - c3)
+- Code(Counter(0)) at (prev + 2, 9) to (start + 0, 17)
+- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 25)
 - Code(Counter(4)) at (prev + 0, 29) to (start + 0, 34)
-- Code(Expression(155, Add)) at (prev + 1, 9) to (start + 0, 17)
-    = (c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5))
-- Code(Expression(157, Add)) at (prev + 0, 20) to (start + 0, 25)
-    = (c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4))
+- Code(Counter(0)) at (prev + 1, 9) to (start + 0, 17)
+- Code(Counter(0)) at (prev + 0, 20) to (start + 0, 25)
 - Code(Counter(5)) at (prev + 0, 29) to (start + 0, 34)
-- Code(Expression(155, Add)) at (prev + 3, 9) to (start + 1, 16)
-    = (c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5))
-- Code(Expression(154, Sub)) at (prev + 2, 5) to (start + 3, 6)
-    = ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)
+- Code(Counter(0)) at (prev + 3, 9) to (start + 1, 16)
+- Code(Expression(3, Sub)) at (prev + 2, 5) to (start + 3, 6)
+    = (c0 - c6)
 - Code(Counter(6)) at (prev + 3, 6) to (start + 0, 7)
-- Code(Expression(153, Add)) at (prev + 3, 9) to (start + 0, 16)
-    = (c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6))
+- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 16)
 - Code(Counter(7)) at (prev + 1, 5) to (start + 3, 6)
-- Code(Expression(152, Sub)) at (prev + 5, 5) to (start + 3, 6)
-    = ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)
-- Code(Expression(151, Add)) at (prev + 5, 8) to (start + 0, 16)
-    = (c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7))
-- Code(Expression(150, Sub)) at (prev + 0, 17) to (start + 2, 6)
-    = ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8)
+- Code(Expression(4, Sub)) at (prev + 5, 5) to (start + 3, 6)
+    = (c0 - c7)
+- Code(Counter(0)) at (prev + 5, 8) to (start + 0, 16)
+- Code(Expression(5, Sub)) at (prev + 0, 17) to (start + 2, 6)
+    = (c0 - c8)
 - Code(Counter(8)) at (prev + 2, 6) to (start + 0, 7)
-- Code(Expression(149, Add)) at (prev + 2, 8) to (start + 0, 15)
-    = (c8 + ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8))
+- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 15)
 - Code(Counter(9)) at (prev + 0, 16) to (start + 2, 6)
-- Code(Expression(148, Sub)) at (prev + 2, 12) to (start + 2, 6)
-    = ((c8 + ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8)) - c9)
-- Code(Expression(147, Add)) at (prev + 3, 1) to (start + 0, 2)
-    = (c9 + ((c8 + ((c7 + ((c6 + ((c5 + ((c4 + ((c3 + ((c2 + ((c1 + (c0 - c1)) - c2)) - c3)) - c4)) - c5)) - c6)) - c7)) - c8)) - c9))
+- Code(Expression(6, Sub)) at (prev + 2, 12) to (start + 2, 6)
+    = (c0 - c9)
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/loops_branches.cov-map b/tests/coverage/loops_branches.cov-map
index 8dc3532..9187dcb 100644
--- a/tests/coverage/loops_branches.cov-map
+++ b/tests/coverage/loops_branches.cov-map
@@ -1,57 +1,50 @@
 Function name: <loops_branches::DebugTest as core::fmt::Debug>::fmt
-Raw bytes (249): 0x[01, 01, 31, 05, 00, 00, 02, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, bf, 01, c3, 01, 0d, 00, 11, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, ab, 01, 11, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, a3, 01, 19, 25, a6, 01, ab, 01, 11, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 07, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, b6, 01, 03, 0d, 00, 0e, bb, 01, 00, 12, 00, 17, b6, 01, 01, 10, 00, 14, b2, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, ae, 01, 01, 12, 00, 13, ab, 01, 01, 11, 00, 22, a6, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, 9f, 01, 01, 05, 00, 06]
+Raw bytes (228): 0x[01, 01, 2a, 05, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, a3, 01, a7, 01, 0d, 00, 11, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 96, 01, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 96, 01, 11, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 8f, 01, 19, 25, 92, 01, 96, 01, 11, 9a, 01, 00, 9f, 01, 19, a3, 01, a7, 01, 0d, 00, 11, 00, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 05, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, 9a, 01, 03, 0d, 00, 0e, 9f, 01, 00, 12, 00, 17, 9a, 01, 01, 10, 00, 14, 96, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 46, 01, 12, 00, 13, 96, 01, 01, 11, 00, 22, 92, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, 8b, 01, 01, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 49
+Number of expressions: 42
 - expression 0 operands: lhs = Counter(1), rhs = Zero
-- expression 1 operands: lhs = Zero, rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Expression(46, Add), rhs = Counter(6)
-- expression 3 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 4 operands: lhs = Counter(3), rhs = Zero
-- expression 5 operands: lhs = Counter(4), rhs = Zero
-- expression 6 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 7 operands: lhs = Counter(3), rhs = Zero
-- expression 8 operands: lhs = Counter(4), rhs = Zero
-- expression 9 operands: lhs = Expression(46, Add), rhs = Counter(6)
-- expression 10 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 11 operands: lhs = Counter(3), rhs = Zero
-- expression 12 operands: lhs = Counter(4), rhs = Zero
-- expression 13 operands: lhs = Expression(45, Sub), rhs = Zero
-- expression 14 operands: lhs = Expression(46, Add), rhs = Counter(6)
-- expression 15 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 16 operands: lhs = Counter(3), rhs = Zero
-- expression 17 operands: lhs = Counter(4), rhs = Zero
-- expression 18 operands: lhs = Expression(44, Sub), rhs = Zero
-- expression 19 operands: lhs = Expression(45, Sub), rhs = Zero
-- expression 20 operands: lhs = Expression(46, Add), rhs = Counter(6)
-- expression 21 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 22 operands: lhs = Counter(3), rhs = Zero
-- expression 23 operands: lhs = Counter(4), rhs = Zero
-- expression 24 operands: lhs = Zero, rhs = Expression(43, Sub)
-- expression 25 operands: lhs = Expression(44, Sub), rhs = Zero
-- expression 26 operands: lhs = Expression(45, Sub), rhs = Zero
-- expression 27 operands: lhs = Expression(46, Add), rhs = Counter(6)
-- expression 28 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 29 operands: lhs = Counter(3), rhs = Zero
-- expression 30 operands: lhs = Counter(4), rhs = Zero
-- expression 31 operands: lhs = Expression(42, Add), rhs = Counter(4)
-- expression 32 operands: lhs = Zero, rhs = Expression(43, Sub)
-- expression 33 operands: lhs = Expression(44, Sub), rhs = Zero
-- expression 34 operands: lhs = Expression(45, Sub), rhs = Zero
-- expression 35 operands: lhs = Expression(46, Add), rhs = Counter(6)
-- expression 36 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 37 operands: lhs = Counter(3), rhs = Zero
-- expression 38 operands: lhs = Counter(4), rhs = Zero
-- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(6)
-- expression 40 operands: lhs = Counter(9), rhs = Expression(41, Sub)
-- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(4)
-- expression 42 operands: lhs = Zero, rhs = Expression(43, Sub)
-- expression 43 operands: lhs = Expression(44, Sub), rhs = Zero
-- expression 44 operands: lhs = Expression(45, Sub), rhs = Zero
-- expression 45 operands: lhs = Expression(46, Add), rhs = Counter(6)
-- expression 46 operands: lhs = Expression(47, Add), rhs = Expression(48, Add)
-- expression 47 operands: lhs = Counter(3), rhs = Zero
-- expression 48 operands: lhs = Counter(4), rhs = Zero
+- expression 1 operands: lhs = Expression(39, Add), rhs = Counter(6)
+- expression 2 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 3 operands: lhs = Counter(3), rhs = Zero
+- expression 4 operands: lhs = Counter(4), rhs = Zero
+- expression 5 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 6 operands: lhs = Counter(3), rhs = Zero
+- expression 7 operands: lhs = Counter(4), rhs = Zero
+- expression 8 operands: lhs = Expression(39, Add), rhs = Counter(6)
+- expression 9 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 10 operands: lhs = Counter(3), rhs = Zero
+- expression 11 operands: lhs = Counter(4), rhs = Zero
+- expression 12 operands: lhs = Expression(38, Sub), rhs = Zero
+- expression 13 operands: lhs = Expression(39, Add), rhs = Counter(6)
+- expression 14 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 15 operands: lhs = Counter(3), rhs = Zero
+- expression 16 operands: lhs = Counter(4), rhs = Zero
+- expression 17 operands: lhs = Expression(37, Sub), rhs = Zero
+- expression 18 operands: lhs = Expression(38, Sub), rhs = Zero
+- expression 19 operands: lhs = Expression(39, Add), rhs = Counter(6)
+- expression 20 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 21 operands: lhs = Counter(3), rhs = Zero
+- expression 22 operands: lhs = Counter(4), rhs = Zero
+- expression 23 operands: lhs = Expression(38, Sub), rhs = Zero
+- expression 24 operands: lhs = Expression(39, Add), rhs = Counter(6)
+- expression 25 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 26 operands: lhs = Counter(3), rhs = Zero
+- expression 27 operands: lhs = Counter(4), rhs = Zero
+- expression 28 operands: lhs = Expression(37, Sub), rhs = Counter(4)
+- expression 29 operands: lhs = Expression(38, Sub), rhs = Zero
+- expression 30 operands: lhs = Expression(39, Add), rhs = Counter(6)
+- expression 31 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 32 operands: lhs = Counter(3), rhs = Zero
+- expression 33 operands: lhs = Counter(4), rhs = Zero
+- expression 34 operands: lhs = Expression(35, Add), rhs = Counter(6)
+- expression 35 operands: lhs = Counter(9), rhs = Expression(36, Sub)
+- expression 36 operands: lhs = Expression(37, Sub), rhs = Counter(4)
+- expression 37 operands: lhs = Expression(38, Sub), rhs = Zero
+- expression 38 operands: lhs = Expression(39, Add), rhs = Counter(6)
+- expression 39 operands: lhs = Expression(40, Add), rhs = Expression(41, Add)
+- expression 40 operands: lhs = Counter(3), rhs = Zero
+- expression 41 operands: lhs = Counter(4), rhs = Zero
 Number of file 0 mappings: 20
 - Code(Counter(0)) at (prev + 9, 5) to (start + 1, 16)
 - Code(Counter(1)) at (prev + 2, 16) to (start + 0, 21)
@@ -59,87 +52,78 @@
 - Code(Zero) at (prev + 0, 28) to (start + 0, 30)
 - Code(Expression(0, Sub)) at (prev + 1, 14) to (start + 0, 15)
     = (c1 - Zero)
-- Code(Expression(1, Add)) at (prev + 1, 13) to (start + 0, 30)
-    = (Zero + (c1 - Zero))
+- Code(Counter(1)) at (prev + 1, 13) to (start + 0, 30)
 - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31)
 - Code(Zero) at (prev + 1, 16) to (start + 1, 10)
-- Code(Expression(45, Sub)) at (prev + 3, 13) to (start + 0, 14)
+- Code(Expression(38, Sub)) at (prev + 3, 13) to (start + 0, 14)
     = (((c3 + Zero) + (c4 + Zero)) - c6)
-- Code(Expression(46, Add)) at (prev + 0, 18) to (start + 0, 23)
+- Code(Expression(39, Add)) at (prev + 0, 18) to (start + 0, 23)
     = ((c3 + Zero) + (c4 + Zero))
-- Code(Expression(45, Sub)) at (prev + 1, 16) to (start + 0, 20)
+- Code(Expression(38, Sub)) at (prev + 1, 16) to (start + 0, 20)
     = (((c3 + Zero) + (c4 + Zero)) - c6)
-- Code(Expression(44, Sub)) at (prev + 1, 20) to (start + 0, 25)
+- Code(Expression(37, Sub)) at (prev + 1, 20) to (start + 0, 25)
     = ((((c3 + Zero) + (c4 + Zero)) - c6) - Zero)
 - Code(Zero) at (prev + 1, 27) to (start + 0, 31)
 - Code(Zero) at (prev + 0, 32) to (start + 0, 34)
-- Code(Expression(43, Sub)) at (prev + 1, 18) to (start + 0, 19)
+- Code(Expression(17, Sub)) at (prev + 1, 18) to (start + 0, 19)
     = (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero)
-- Code(Expression(42, Add)) at (prev + 1, 17) to (start + 0, 34)
-    = (Zero + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero))
-- Code(Expression(41, Sub)) at (prev + 0, 34) to (start + 0, 35)
-    = ((Zero + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero)) - c4)
+- Code(Expression(37, Sub)) at (prev + 1, 17) to (start + 0, 34)
+    = ((((c3 + Zero) + (c4 + Zero)) - c6) - Zero)
+- Code(Expression(36, Sub)) at (prev + 0, 34) to (start + 0, 35)
+    = (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - c4)
 - Code(Zero) at (prev + 1, 20) to (start + 1, 14)
 - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15)
-- Code(Expression(39, Add)) at (prev + 1, 5) to (start + 0, 6)
-    = ((c9 + ((Zero + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero)) - c4)) + c6)
+- Code(Expression(34, Add)) at (prev + 1, 5) to (start + 0, 6)
+    = ((c9 + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - c4)) + c6)
 
 Function name: <loops_branches::DisplayTest as core::fmt::Display>::fmt
-Raw bytes (253): 0x[01, 01, 33, 01, 00, 02, 00, 00, 0e, 02, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, c7, 01, cb, 01, 00, 0d, 00, 15, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, ba, 01, 00, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, 00, b6, 01, ba, 01, 00, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, b3, 01, 15, 00, b6, 01, ba, 01, 00, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, ab, 01, 25, ae, 01, 19, b3, 01, 15, 00, b6, 01, ba, 01, 00, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 0e, 01, 0e, 00, 0f, 0b, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, be, 01, 02, 0d, 00, 0e, c3, 01, 00, 12, 00, 17, be, 01, 01, 10, 00, 15, 00, 00, 16, 01, 0e, ba, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, b6, 01, 01, 12, 00, 13, b3, 01, 01, 11, 00, 22, ae, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, a7, 01, 01, 05, 00, 06]
+Raw bytes (230): 0x[01, 01, 2b, 01, 00, 02, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, a7, 01, ab, 01, 00, 0d, 00, 15, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9a, 01, 00, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 9a, 01, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 93, 01, 25, 96, 01, 19, 9a, 01, 15, 9e, 01, 00, a3, 01, 19, a7, 01, ab, 01, 00, 0d, 00, 15, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 06, 01, 0e, 00, 0f, 02, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 9e, 01, 02, 0d, 00, 0e, a3, 01, 00, 12, 00, 17, 9e, 01, 01, 10, 00, 15, 00, 00, 16, 01, 0e, 9a, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, 4a, 01, 12, 00, 13, 9a, 01, 01, 11, 00, 22, 96, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, 8f, 01, 01, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 51
+Number of expressions: 43
 - expression 0 operands: lhs = Counter(0), rhs = Zero
 - expression 1 operands: lhs = Expression(0, Sub), rhs = Zero
-- expression 2 operands: lhs = Zero, rhs = Expression(3, Sub)
-- expression 3 operands: lhs = Expression(0, Sub), rhs = Zero
-- expression 4 operands: lhs = Expression(48, Add), rhs = Counter(6)
-- expression 5 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 6 operands: lhs = Zero, rhs = Counter(3)
-- expression 7 operands: lhs = Zero, rhs = Counter(5)
-- expression 8 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 9 operands: lhs = Zero, rhs = Counter(3)
-- expression 10 operands: lhs = Zero, rhs = Counter(5)
-- expression 11 operands: lhs = Expression(48, Add), rhs = Counter(6)
-- expression 12 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 13 operands: lhs = Zero, rhs = Counter(3)
-- expression 14 operands: lhs = Zero, rhs = Counter(5)
-- expression 15 operands: lhs = Expression(47, Sub), rhs = Zero
-- expression 16 operands: lhs = Expression(48, Add), rhs = Counter(6)
-- expression 17 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 18 operands: lhs = Zero, rhs = Counter(3)
-- expression 19 operands: lhs = Zero, rhs = Counter(5)
-- expression 20 operands: lhs = Expression(46, Sub), rhs = Zero
-- expression 21 operands: lhs = Expression(47, Sub), rhs = Zero
-- expression 22 operands: lhs = Expression(48, Add), rhs = Counter(6)
-- expression 23 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 24 operands: lhs = Zero, rhs = Counter(3)
-- expression 25 operands: lhs = Zero, rhs = Counter(5)
-- expression 26 operands: lhs = Zero, rhs = Expression(45, Sub)
-- expression 27 operands: lhs = Expression(46, Sub), rhs = Zero
-- expression 28 operands: lhs = Expression(47, Sub), rhs = Zero
-- expression 29 operands: lhs = Expression(48, Add), rhs = Counter(6)
-- expression 30 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 31 operands: lhs = Zero, rhs = Counter(3)
-- expression 32 operands: lhs = Zero, rhs = Counter(5)
-- expression 33 operands: lhs = Expression(44, Add), rhs = Counter(5)
-- expression 34 operands: lhs = Zero, rhs = Expression(45, Sub)
-- expression 35 operands: lhs = Expression(46, Sub), rhs = Zero
-- expression 36 operands: lhs = Expression(47, Sub), rhs = Zero
-- expression 37 operands: lhs = Expression(48, Add), rhs = Counter(6)
-- expression 38 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 39 operands: lhs = Zero, rhs = Counter(3)
-- expression 40 operands: lhs = Zero, rhs = Counter(5)
-- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(9)
-- expression 42 operands: lhs = Expression(43, Sub), rhs = Counter(6)
-- expression 43 operands: lhs = Expression(44, Add), rhs = Counter(5)
-- expression 44 operands: lhs = Zero, rhs = Expression(45, Sub)
-- expression 45 operands: lhs = Expression(46, Sub), rhs = Zero
-- expression 46 operands: lhs = Expression(47, Sub), rhs = Zero
-- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(6)
-- expression 48 operands: lhs = Expression(49, Add), rhs = Expression(50, Add)
-- expression 49 operands: lhs = Zero, rhs = Counter(3)
-- expression 50 operands: lhs = Zero, rhs = Counter(5)
+- expression 2 operands: lhs = Expression(40, Add), rhs = Counter(6)
+- expression 3 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 4 operands: lhs = Zero, rhs = Counter(3)
+- expression 5 operands: lhs = Zero, rhs = Counter(5)
+- expression 6 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 7 operands: lhs = Zero, rhs = Counter(3)
+- expression 8 operands: lhs = Zero, rhs = Counter(5)
+- expression 9 operands: lhs = Expression(40, Add), rhs = Counter(6)
+- expression 10 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 11 operands: lhs = Zero, rhs = Counter(3)
+- expression 12 operands: lhs = Zero, rhs = Counter(5)
+- expression 13 operands: lhs = Expression(39, Sub), rhs = Zero
+- expression 14 operands: lhs = Expression(40, Add), rhs = Counter(6)
+- expression 15 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 16 operands: lhs = Zero, rhs = Counter(3)
+- expression 17 operands: lhs = Zero, rhs = Counter(5)
+- expression 18 operands: lhs = Expression(38, Sub), rhs = Zero
+- expression 19 operands: lhs = Expression(39, Sub), rhs = Zero
+- expression 20 operands: lhs = Expression(40, Add), rhs = Counter(6)
+- expression 21 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 22 operands: lhs = Zero, rhs = Counter(3)
+- expression 23 operands: lhs = Zero, rhs = Counter(5)
+- expression 24 operands: lhs = Expression(39, Sub), rhs = Zero
+- expression 25 operands: lhs = Expression(40, Add), rhs = Counter(6)
+- expression 26 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 27 operands: lhs = Zero, rhs = Counter(3)
+- expression 28 operands: lhs = Zero, rhs = Counter(5)
+- expression 29 operands: lhs = Expression(38, Sub), rhs = Counter(5)
+- expression 30 operands: lhs = Expression(39, Sub), rhs = Zero
+- expression 31 operands: lhs = Expression(40, Add), rhs = Counter(6)
+- expression 32 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 33 operands: lhs = Zero, rhs = Counter(3)
+- expression 34 operands: lhs = Zero, rhs = Counter(5)
+- expression 35 operands: lhs = Expression(36, Add), rhs = Counter(9)
+- expression 36 operands: lhs = Expression(37, Sub), rhs = Counter(6)
+- expression 37 operands: lhs = Expression(38, Sub), rhs = Counter(5)
+- expression 38 operands: lhs = Expression(39, Sub), rhs = Zero
+- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(6)
+- expression 40 operands: lhs = Expression(41, Add), rhs = Expression(42, Add)
+- expression 41 operands: lhs = Zero, rhs = Counter(3)
+- expression 42 operands: lhs = Zero, rhs = Counter(5)
 Number of file 0 mappings: 20
 - Code(Counter(0)) at (prev + 34, 5) to (start + 1, 17)
 - Code(Zero) at (prev + 1, 18) to (start + 1, 10)
@@ -147,31 +131,31 @@
     = (c0 - Zero)
 - Code(Zero) at (prev + 1, 23) to (start + 0, 27)
 - Code(Zero) at (prev + 0, 28) to (start + 0, 30)
-- Code(Expression(3, Sub)) at (prev + 1, 14) to (start + 0, 15)
+- Code(Expression(1, Sub)) at (prev + 1, 14) to (start + 0, 15)
     = ((c0 - Zero) - Zero)
-- Code(Expression(2, Add)) at (prev + 1, 13) to (start + 0, 30)
-    = (Zero + ((c0 - Zero) - Zero))
+- Code(Expression(0, Sub)) at (prev + 1, 13) to (start + 0, 30)
+    = (c0 - Zero)
 - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31)
-- Code(Expression(47, Sub)) at (prev + 2, 13) to (start + 0, 14)
+- Code(Expression(39, Sub)) at (prev + 2, 13) to (start + 0, 14)
     = (((Zero + c3) + (Zero + c5)) - c6)
-- Code(Expression(48, Add)) at (prev + 0, 18) to (start + 0, 23)
+- Code(Expression(40, Add)) at (prev + 0, 18) to (start + 0, 23)
     = ((Zero + c3) + (Zero + c5))
-- Code(Expression(47, Sub)) at (prev + 1, 16) to (start + 0, 21)
+- Code(Expression(39, Sub)) at (prev + 1, 16) to (start + 0, 21)
     = (((Zero + c3) + (Zero + c5)) - c6)
 - Code(Zero) at (prev + 0, 22) to (start + 1, 14)
-- Code(Expression(46, Sub)) at (prev + 2, 20) to (start + 0, 25)
+- Code(Expression(38, Sub)) at (prev + 2, 20) to (start + 0, 25)
     = ((((Zero + c3) + (Zero + c5)) - c6) - Zero)
 - Code(Zero) at (prev + 1, 27) to (start + 0, 31)
 - Code(Zero) at (prev + 0, 32) to (start + 0, 34)
-- Code(Expression(45, Sub)) at (prev + 1, 18) to (start + 0, 19)
+- Code(Expression(18, Sub)) at (prev + 1, 18) to (start + 0, 19)
     = (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero)
-- Code(Expression(44, Add)) at (prev + 1, 17) to (start + 0, 34)
-    = (Zero + (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero))
-- Code(Expression(43, Sub)) at (prev + 0, 34) to (start + 0, 35)
-    = ((Zero + (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero)) - c5)
+- Code(Expression(38, Sub)) at (prev + 1, 17) to (start + 0, 34)
+    = ((((Zero + c3) + (Zero + c5)) - c6) - Zero)
+- Code(Expression(37, Sub)) at (prev + 0, 34) to (start + 0, 35)
+    = (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - c5)
 - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15)
-- Code(Expression(41, Add)) at (prev + 1, 5) to (start + 0, 6)
-    = ((((Zero + (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero)) - c5) + c6) + c9)
+- Code(Expression(35, Add)) at (prev + 1, 5) to (start + 0, 6)
+    = (((((((Zero + c3) + (Zero + c5)) - c6) - Zero) - c5) + c6) + c9)
 
 Function name: loops_branches::main
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 37, 01, 05, 02]
diff --git a/tests/coverage/match_or_pattern.cov-map b/tests/coverage/match_or_pattern.cov-map
index d63407a..60b7024 100644
--- a/tests/coverage/match_or_pattern.cov-map
+++ b/tests/coverage/match_or_pattern.cov-map
@@ -1,83 +1,75 @@
 Function name: match_or_pattern::main
-Raw bytes (202): 0x[01, 01, 23, 01, 05, 05, 02, 09, 0d, 2f, 11, 09, 0d, 2b, 15, 2f, 11, 09, 0d, 15, 26, 2b, 15, 2f, 11, 09, 0d, 19, 1d, 57, 21, 19, 1d, 53, 25, 57, 21, 19, 1d, 25, 4e, 53, 25, 57, 21, 19, 1d, 29, 2d, 7f, 31, 29, 2d, 7b, 35, 7f, 31, 29, 2d, 35, 76, 7b, 35, 7f, 31, 29, 2d, 39, 3d, 8b, 01, 41, 39, 3d, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 06, 00, 07, 07, 01, 0b, 00, 11, 11, 03, 1b, 00, 1d, 2f, 01, 0e, 00, 10, 2b, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 26, 03, 06, 00, 07, 23, 01, 0b, 00, 11, 21, 01, 1b, 00, 1d, 57, 01, 0e, 00, 10, 53, 02, 08, 00, 0f, 25, 00, 10, 03, 06, 4e, 03, 06, 00, 07, 4b, 01, 0b, 00, 11, 31, 01, 1b, 00, 1d, 7f, 01, 0e, 00, 10, 7b, 02, 08, 00, 0f, 35, 00, 10, 03, 06, 76, 03, 06, 00, 07, 73, 01, 0b, 00, 11, 41, 01, 1b, 00, 1d, 8b, 01, 01, 0e, 00, 10, 87, 01, 02, 01, 00, 02]
+Raw bytes (185): 0x[01, 01, 1c, 01, 05, 09, 0d, 23, 11, 09, 0d, 1f, 15, 23, 11, 09, 0d, 23, 11, 09, 0d, 19, 1d, 43, 21, 19, 1d, 3f, 25, 43, 21, 19, 1d, 43, 21, 19, 1d, 29, 2d, 63, 31, 29, 2d, 5f, 35, 63, 31, 29, 2d, 63, 31, 29, 2d, 39, 3d, 6f, 41, 39, 3d, 19, 01, 01, 01, 08, 0f, 05, 08, 10, 03, 06, 02, 03, 06, 00, 07, 01, 01, 0b, 00, 11, 11, 03, 1b, 00, 1d, 23, 01, 0e, 00, 10, 1f, 02, 08, 00, 0f, 15, 00, 10, 03, 06, 12, 03, 06, 00, 07, 1f, 01, 0b, 00, 11, 21, 01, 1b, 00, 1d, 43, 01, 0e, 00, 10, 3f, 02, 08, 00, 0f, 25, 00, 10, 03, 06, 32, 03, 06, 00, 07, 3f, 01, 0b, 00, 11, 31, 01, 1b, 00, 1d, 63, 01, 0e, 00, 10, 5f, 02, 08, 00, 0f, 35, 00, 10, 03, 06, 52, 03, 06, 00, 07, 5f, 01, 0b, 00, 11, 41, 01, 1b, 00, 1d, 6f, 01, 0e, 00, 10, 6b, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 35
+Number of expressions: 28
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 3 operands: lhs = Expression(11, Add), rhs = Counter(4)
-- expression 4 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 5 operands: lhs = Expression(10, Add), rhs = Counter(5)
-- expression 6 operands: lhs = Expression(11, Add), rhs = Counter(4)
-- expression 7 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 8 operands: lhs = Counter(5), rhs = Expression(9, Sub)
-- expression 9 operands: lhs = Expression(10, Add), rhs = Counter(5)
-- expression 10 operands: lhs = Expression(11, Add), rhs = Counter(4)
-- expression 11 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 12 operands: lhs = Counter(6), rhs = Counter(7)
-- expression 13 operands: lhs = Expression(21, Add), rhs = Counter(8)
+- expression 1 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 2 operands: lhs = Expression(8, Add), rhs = Counter(4)
+- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 4 operands: lhs = Expression(7, Add), rhs = Counter(5)
+- expression 5 operands: lhs = Expression(8, Add), rhs = Counter(4)
+- expression 6 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(4)
+- expression 8 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 9 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 10 operands: lhs = Expression(16, Add), rhs = Counter(8)
+- expression 11 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 12 operands: lhs = Expression(15, Add), rhs = Counter(9)
+- expression 13 operands: lhs = Expression(16, Add), rhs = Counter(8)
 - expression 14 operands: lhs = Counter(6), rhs = Counter(7)
-- expression 15 operands: lhs = Expression(20, Add), rhs = Counter(9)
-- expression 16 operands: lhs = Expression(21, Add), rhs = Counter(8)
-- expression 17 operands: lhs = Counter(6), rhs = Counter(7)
-- expression 18 operands: lhs = Counter(9), rhs = Expression(19, Sub)
-- expression 19 operands: lhs = Expression(20, Add), rhs = Counter(9)
-- expression 20 operands: lhs = Expression(21, Add), rhs = Counter(8)
-- expression 21 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 15 operands: lhs = Expression(16, Add), rhs = Counter(8)
+- expression 16 operands: lhs = Counter(6), rhs = Counter(7)
+- expression 17 operands: lhs = Counter(10), rhs = Counter(11)
+- expression 18 operands: lhs = Expression(24, Add), rhs = Counter(12)
+- expression 19 operands: lhs = Counter(10), rhs = Counter(11)
+- expression 20 operands: lhs = Expression(23, Add), rhs = Counter(13)
+- expression 21 operands: lhs = Expression(24, Add), rhs = Counter(12)
 - expression 22 operands: lhs = Counter(10), rhs = Counter(11)
-- expression 23 operands: lhs = Expression(31, Add), rhs = Counter(12)
+- expression 23 operands: lhs = Expression(24, Add), rhs = Counter(12)
 - expression 24 operands: lhs = Counter(10), rhs = Counter(11)
-- expression 25 operands: lhs = Expression(30, Add), rhs = Counter(13)
-- expression 26 operands: lhs = Expression(31, Add), rhs = Counter(12)
-- expression 27 operands: lhs = Counter(10), rhs = Counter(11)
-- expression 28 operands: lhs = Counter(13), rhs = Expression(29, Sub)
-- expression 29 operands: lhs = Expression(30, Add), rhs = Counter(13)
-- expression 30 operands: lhs = Expression(31, Add), rhs = Counter(12)
-- expression 31 operands: lhs = Counter(10), rhs = Counter(11)
-- expression 32 operands: lhs = Counter(14), rhs = Counter(15)
-- expression 33 operands: lhs = Expression(34, Add), rhs = Counter(16)
-- expression 34 operands: lhs = Counter(14), rhs = Counter(15)
+- expression 25 operands: lhs = Counter(14), rhs = Counter(15)
+- expression 26 operands: lhs = Expression(27, Add), rhs = Counter(16)
+- expression 27 operands: lhs = Counter(14), rhs = Counter(15)
 Number of file 0 mappings: 25
 - Code(Counter(0)) at (prev + 1, 1) to (start + 8, 15)
 - Code(Counter(1)) at (prev + 8, 16) to (start + 3, 6)
 - Code(Expression(0, Sub)) at (prev + 3, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 11) to (start + 0, 17)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 11) to (start + 0, 17)
 - Code(Counter(4)) at (prev + 3, 27) to (start + 0, 29)
-- Code(Expression(11, Add)) at (prev + 1, 14) to (start + 0, 16)
+- Code(Expression(8, Add)) at (prev + 1, 14) to (start + 0, 16)
     = (c2 + c3)
-- Code(Expression(10, Add)) at (prev + 2, 8) to (start + 0, 15)
+- Code(Expression(7, Add)) at (prev + 2, 8) to (start + 0, 15)
     = ((c2 + c3) + c4)
 - Code(Counter(5)) at (prev + 0, 16) to (start + 3, 6)
-- Code(Expression(9, Sub)) at (prev + 3, 6) to (start + 0, 7)
+- Code(Expression(4, Sub)) at (prev + 3, 6) to (start + 0, 7)
     = (((c2 + c3) + c4) - c5)
-- Code(Expression(8, Add)) at (prev + 1, 11) to (start + 0, 17)
-    = (c5 + (((c2 + c3) + c4) - c5))
+- Code(Expression(7, Add)) at (prev + 1, 11) to (start + 0, 17)
+    = ((c2 + c3) + c4)
 - Code(Counter(8)) at (prev + 1, 27) to (start + 0, 29)
-- Code(Expression(21, Add)) at (prev + 1, 14) to (start + 0, 16)
+- Code(Expression(16, Add)) at (prev + 1, 14) to (start + 0, 16)
     = (c6 + c7)
-- Code(Expression(20, Add)) at (prev + 2, 8) to (start + 0, 15)
+- Code(Expression(15, Add)) at (prev + 2, 8) to (start + 0, 15)
     = ((c6 + c7) + c8)
 - Code(Counter(9)) at (prev + 0, 16) to (start + 3, 6)
-- Code(Expression(19, Sub)) at (prev + 3, 6) to (start + 0, 7)
+- Code(Expression(12, Sub)) at (prev + 3, 6) to (start + 0, 7)
     = (((c6 + c7) + c8) - c9)
-- Code(Expression(18, Add)) at (prev + 1, 11) to (start + 0, 17)
-    = (c9 + (((c6 + c7) + c8) - c9))
+- Code(Expression(15, Add)) at (prev + 1, 11) to (start + 0, 17)
+    = ((c6 + c7) + c8)
 - Code(Counter(12)) at (prev + 1, 27) to (start + 0, 29)
-- Code(Expression(31, Add)) at (prev + 1, 14) to (start + 0, 16)
+- Code(Expression(24, Add)) at (prev + 1, 14) to (start + 0, 16)
     = (c10 + c11)
-- Code(Expression(30, Add)) at (prev + 2, 8) to (start + 0, 15)
+- Code(Expression(23, Add)) at (prev + 2, 8) to (start + 0, 15)
     = ((c10 + c11) + c12)
 - Code(Counter(13)) at (prev + 0, 16) to (start + 3, 6)
-- Code(Expression(29, Sub)) at (prev + 3, 6) to (start + 0, 7)
+- Code(Expression(20, Sub)) at (prev + 3, 6) to (start + 0, 7)
     = (((c10 + c11) + c12) - c13)
-- Code(Expression(28, Add)) at (prev + 1, 11) to (start + 0, 17)
-    = (c13 + (((c10 + c11) + c12) - c13))
+- Code(Expression(23, Add)) at (prev + 1, 11) to (start + 0, 17)
+    = ((c10 + c11) + c12)
 - Code(Counter(16)) at (prev + 1, 27) to (start + 0, 29)
-- Code(Expression(34, Add)) at (prev + 1, 14) to (start + 0, 16)
+- Code(Expression(27, Add)) at (prev + 1, 14) to (start + 0, 16)
     = (c14 + c15)
-- Code(Expression(33, Add)) at (prev + 2, 1) to (start + 0, 2)
+- Code(Expression(26, Add)) at (prev + 2, 1) to (start + 0, 2)
     = ((c14 + c15) + c16)
 
diff --git a/tests/coverage/no_cov_crate.cov-map b/tests/coverage/no_cov_crate.cov-map
index 05b6448..e623f64 100644
--- a/tests/coverage/no_cov_crate.cov-map
+++ b/tests/coverage/no_cov_crate.cov-map
@@ -47,32 +47,28 @@
 - Code(Counter(0)) at (prev + 63, 5) to (start + 11, 6)
 
 Function name: no_cov_crate::nested_fns::outer_both_covered::inner
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 43, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 07, 03, 09, 00, 0a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 43, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 67, 9) to (start + 1, 23)
 - Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14)
 - Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 9) to (start + 0, 10)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10)
 
 Function name: no_cov_crate::nested_fns::outer_not_covered::inner
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 26, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 07, 03, 09, 00, 0a]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 26, 09, 01, 17, 05, 01, 18, 02, 0e, 02, 02, 14, 02, 0e, 01, 03, 09, 00, 0a]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 38, 9) to (start + 1, 23)
 - Code(Counter(1)) at (prev + 1, 24) to (start + 2, 14)
 - Code(Expression(0, Sub)) at (prev + 2, 20) to (start + 2, 14)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 3, 9) to (start + 0, 10)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 3, 9) to (start + 0, 10)
 
diff --git a/tests/coverage/overflow.cov-map b/tests/coverage/overflow.cov-map
index 39a5c05..cb31f3d 100644
--- a/tests/coverage/overflow.cov-map
+++ b/tests/coverage/overflow.cov-map
@@ -27,17 +27,15 @@
 - Code(Counter(4)) at (prev + 2, 5) to (start + 1, 2)
 
 Function name: overflow::might_overflow
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 05, 01, 01, 12, 05, 01, 13, 02, 06, 02, 02, 06, 00, 07, 07, 01, 09, 05, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 05, 01, 01, 12, 05, 01, 13, 02, 06, 02, 02, 06, 00, 07, 01, 01, 09, 05, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 5, 1) to (start + 1, 18)
 - Code(Counter(1)) at (prev + 1, 19) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 9) to (start + 5, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 9) to (start + 5, 2)
 
diff --git a/tests/coverage/simple_loop.cov-map b/tests/coverage/simple_loop.cov-map
index 0a342cb..541f7bf 100644
--- a/tests/coverage/simple_loop.cov-map
+++ b/tests/coverage/simple_loop.cov-map
@@ -1,27 +1,18 @@
 Function name: simple_loop::main
-Raw bytes (57): 0x[01, 01, 09, 01, 05, 23, 09, 05, 02, 1f, 09, 23, 09, 05, 02, 1f, 09, 23, 09, 05, 02, 07, 01, 04, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 06, 00, 07, 1f, 05, 0d, 02, 0e, 1a, 04, 0d, 00, 12, 09, 02, 0a, 03, 0a, 1a, 06, 01, 00, 02]
+Raw bytes (43): 0x[01, 01, 02, 01, 05, 01, 09, 07, 01, 04, 01, 09, 10, 05, 0a, 05, 05, 06, 02, 05, 06, 00, 07, 07, 05, 0d, 02, 0e, 01, 04, 0d, 00, 12, 09, 02, 0a, 03, 0a, 01, 06, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 9
+Number of expressions: 2
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(8, Add), rhs = Counter(2)
-- expression 2 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 3 operands: lhs = Expression(7, Add), rhs = Counter(2)
-- expression 4 operands: lhs = Expression(8, Add), rhs = Counter(2)
-- expression 5 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(2)
-- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(2)
-- expression 8 operands: lhs = Counter(1), rhs = Expression(0, Sub)
+- expression 1 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 7
 - Code(Counter(0)) at (prev + 4, 1) to (start + 9, 16)
 - Code(Counter(1)) at (prev + 10, 5) to (start + 5, 6)
 - Code(Expression(0, Sub)) at (prev + 5, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(7, Add)) at (prev + 5, 13) to (start + 2, 14)
-    = ((c1 + (c0 - c1)) + c2)
-- Code(Expression(6, Sub)) at (prev + 4, 13) to (start + 0, 18)
-    = (((c1 + (c0 - c1)) + c2) - c2)
+- Code(Expression(1, Add)) at (prev + 5, 13) to (start + 2, 14)
+    = (c0 + c2)
+- Code(Counter(0)) at (prev + 4, 13) to (start + 0, 18)
 - Code(Counter(2)) at (prev + 2, 10) to (start + 3, 10)
-- Code(Expression(6, Sub)) at (prev + 6, 1) to (start + 0, 2)
-    = (((c1 + (c0 - c1)) + c2) - c2)
+- Code(Counter(0)) at (prev + 6, 1) to (start + 0, 2)
 
diff --git a/tests/coverage/simple_match.cov-map b/tests/coverage/simple_match.cov-map
index 7c242e2..49819b2 100644
--- a/tests/coverage/simple_match.cov-map
+++ b/tests/coverage/simple_match.cov-map
@@ -1,32 +1,29 @@
 Function name: simple_match::main
-Raw bytes (78): 0x[01, 01, 0c, 01, 05, 2b, 2f, 05, 02, 09, 0d, 27, 11, 2b, 2f, 05, 02, 09, 0d, 27, 11, 2b, 2f, 05, 02, 09, 0d, 0a, 01, 04, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 27, 05, 09, 00, 0d, 22, 05, 0d, 00, 16, 09, 02, 0d, 00, 0e, 22, 02, 11, 02, 12, 09, 04, 0d, 07, 0e, 0d, 0a, 0d, 00, 0f, 11, 03, 01, 00, 02]
+Raw bytes (72): 0x[01, 01, 09, 01, 05, 01, 23, 09, 0d, 1f, 11, 01, 23, 09, 0d, 1f, 11, 01, 23, 09, 0d, 0a, 01, 04, 01, 07, 0f, 05, 07, 10, 02, 06, 02, 02, 06, 00, 07, 1f, 05, 09, 00, 0d, 1a, 05, 0d, 00, 16, 09, 02, 0d, 00, 0e, 1a, 02, 11, 02, 12, 09, 04, 0d, 07, 0e, 0d, 0a, 0d, 00, 0f, 11, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 12
+Number of expressions: 9
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(10, Add), rhs = Expression(11, Add)
-- expression 2 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 3 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 4 operands: lhs = Expression(9, Add), rhs = Counter(4)
-- expression 5 operands: lhs = Expression(10, Add), rhs = Expression(11, Add)
-- expression 6 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 7 operands: lhs = Counter(2), rhs = Counter(3)
-- expression 8 operands: lhs = Expression(9, Add), rhs = Counter(4)
-- expression 9 operands: lhs = Expression(10, Add), rhs = Expression(11, Add)
-- expression 10 operands: lhs = Counter(1), rhs = Expression(0, Sub)
-- expression 11 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 1 operands: lhs = Counter(0), rhs = Expression(8, Add)
+- expression 2 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 3 operands: lhs = Expression(7, Add), rhs = Counter(4)
+- expression 4 operands: lhs = Counter(0), rhs = Expression(8, Add)
+- expression 5 operands: lhs = Counter(2), rhs = Counter(3)
+- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(4)
+- expression 7 operands: lhs = Counter(0), rhs = Expression(8, Add)
+- expression 8 operands: lhs = Counter(2), rhs = Counter(3)
 Number of file 0 mappings: 10
 - Code(Counter(0)) at (prev + 4, 1) to (start + 7, 15)
 - Code(Counter(1)) at (prev + 7, 16) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(9, Add)) at (prev + 5, 9) to (start + 0, 13)
-    = ((c1 + (c0 - c1)) + (c2 + c3))
-- Code(Expression(8, Sub)) at (prev + 5, 13) to (start + 0, 22)
-    = (((c1 + (c0 - c1)) + (c2 + c3)) - c4)
+- Code(Expression(7, Add)) at (prev + 5, 9) to (start + 0, 13)
+    = (c0 + (c2 + c3))
+- Code(Expression(6, Sub)) at (prev + 5, 13) to (start + 0, 22)
+    = ((c0 + (c2 + c3)) - c4)
 - Code(Counter(2)) at (prev + 2, 13) to (start + 0, 14)
-- Code(Expression(8, Sub)) at (prev + 2, 17) to (start + 2, 18)
-    = (((c1 + (c0 - c1)) + (c2 + c3)) - c4)
+- Code(Expression(6, Sub)) at (prev + 2, 17) to (start + 2, 18)
+    = ((c0 + (c2 + c3)) - c4)
 - Code(Counter(2)) at (prev + 4, 13) to (start + 7, 14)
 - Code(Counter(3)) at (prev + 10, 13) to (start + 0, 15)
 - Code(Counter(4)) at (prev + 3, 1) to (start + 0, 2)
diff --git a/tests/coverage/sort_groups.cov-map b/tests/coverage/sort_groups.cov-map
index 3cbda6f..361b70f 100644
--- a/tests/coverage/sort_groups.cov-map
+++ b/tests/coverage/sort_groups.cov-map
@@ -1,77 +1,67 @@
 Function name: sort_groups::generic_fn::<&str>
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12)
 - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: sort_groups::generic_fn::<()>
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12)
 - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: sort_groups::generic_fn::<char>
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12)
 - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: sort_groups::generic_fn::<i32>
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 11, 01, 01, 0c, 05, 01, 0d, 02, 06, 02, 02, 06, 00, 07, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 17, 1) to (start + 1, 12)
 - Code(Counter(1)) at (prev + 1, 13) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: sort_groups::main
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 06, 01, 04, 23, 05, 04, 24, 02, 06, 02, 02, 06, 00, 07, 07, 01, 05, 02, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 06, 01, 04, 23, 05, 04, 24, 02, 06, 02, 02, 06, 00, 07, 01, 01, 05, 02, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 6, 1) to (start + 4, 35)
 - Code(Counter(1)) at (prev + 4, 36) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 2, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 2, 2)
 
 Function name: sort_groups::other_fn
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 17, 01, 00, 11]
diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map
index 83f1869..49e6c7c 100644
--- a/tests/coverage/try_error_result.cov-map
+++ b/tests/coverage/try_error_result.cov-map
@@ -1,62 +1,54 @@
 Function name: <try_error_result::Thing1>::get_thing_2
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 29, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 1a, 07, 02, 05, 00, 06]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 29, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 1a, 01, 02, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 41, 5) to (start + 1, 24)
 - Code(Counter(1)) at (prev + 2, 13) to (start + 0, 20)
 - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 26)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 2, 5) to (start + 0, 6)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6)
 
 Function name: <try_error_result::Thing2>::call
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 34, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 13, 07, 02, 05, 00, 06]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 34, 05, 01, 18, 05, 02, 0d, 00, 14, 02, 02, 0d, 00, 13, 01, 02, 05, 00, 06]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 52, 5) to (start + 1, 24)
 - Code(Counter(1)) at (prev + 2, 13) to (start + 0, 20)
 - Code(Expression(0, Sub)) at (prev + 2, 13) to (start + 0, 19)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 2, 5) to (start + 0, 6)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 5) to (start + 0, 6)
 
 Function name: try_error_result::call
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 04, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 07, 02, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 04, 01, 01, 14, 05, 02, 09, 00, 10, 02, 02, 09, 00, 0f, 01, 02, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 4, 1) to (start + 1, 20)
 - Code(Counter(1)) at (prev + 2, 9) to (start + 0, 16)
 - Code(Expression(0, Sub)) at (prev + 2, 9) to (start + 0, 15)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 2, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 2, 1) to (start + 0, 2)
 
 Function name: try_error_result::main
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 73, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 07, 01, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 73, 01, 02, 0c, 05, 03, 05, 00, 06, 02, 02, 05, 00, 0b, 01, 01, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 115, 1) to (start + 2, 12)
 - Code(Counter(1)) at (prev + 3, 5) to (start + 0, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 5) to (start + 0, 11)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 1) to (start + 0, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 1) to (start + 0, 2)
 
 Function name: try_error_result::test1
 Raw bytes (75): 0x[01, 01, 08, 01, 07, 00, 09, 03, 0d, 12, 1d, 03, 0d, 1b, 0d, 1f, 00, 11, 00, 0b, 01, 0d, 01, 02, 17, 03, 07, 09, 00, 0e, 12, 02, 09, 04, 1a, 1d, 06, 0d, 00, 29, 11, 00, 29, 00, 2a, 00, 01, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0e, 04, 0d, 00, 2a, 00, 00, 2a, 00, 2b, 0d, 03, 05, 00, 0b, 17, 01, 01, 00, 02]
diff --git a/tests/coverage/unicode.cov-map b/tests/coverage/unicode.cov-map
index aedfb20..06a2c93 100644
--- a/tests/coverage/unicode.cov-map
+++ b/tests/coverage/unicode.cov-map
@@ -1,31 +1,27 @@
 Function name: unicode::main
-Raw bytes (67): 0x[01, 01, 09, 01, 05, 03, 05, 1e, 0d, 22, 09, 03, 05, 11, 1b, 1e, 0d, 22, 09, 03, 05, 09, 01, 0e, 01, 00, 0b, 05, 01, 09, 00, 0c, 03, 00, 10, 00, 1b, 05, 00, 1c, 00, 28, 22, 02, 08, 00, 25, 09, 00, 29, 00, 46, 11, 00, 47, 02, 06, 1b, 02, 06, 00, 07, 17, 02, 05, 01, 02]
+Raw bytes (61): 0x[01, 01, 06, 01, 05, 16, 0d, 01, 09, 11, 13, 16, 0d, 01, 09, 09, 01, 0e, 01, 00, 0b, 05, 01, 09, 00, 0c, 03, 00, 10, 00, 1b, 05, 00, 1c, 00, 28, 01, 02, 08, 00, 25, 09, 00, 29, 00, 46, 11, 00, 47, 02, 06, 13, 02, 06, 00, 07, 0f, 02, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 9
+Number of expressions: 6
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Expression(0, Add), rhs = Counter(1)
-- expression 2 operands: lhs = Expression(7, Sub), rhs = Counter(3)
-- expression 3 operands: lhs = Expression(8, Sub), rhs = Counter(2)
-- expression 4 operands: lhs = Expression(0, Add), rhs = Counter(1)
-- expression 5 operands: lhs = Counter(4), rhs = Expression(6, Add)
-- expression 6 operands: lhs = Expression(7, Sub), rhs = Counter(3)
-- expression 7 operands: lhs = Expression(8, Sub), rhs = Counter(2)
-- expression 8 operands: lhs = Expression(0, Add), rhs = Counter(1)
+- expression 1 operands: lhs = Expression(5, Sub), rhs = Counter(3)
+- expression 2 operands: lhs = Counter(0), rhs = Counter(2)
+- expression 3 operands: lhs = Counter(4), rhs = Expression(4, Add)
+- expression 4 operands: lhs = Expression(5, Sub), rhs = Counter(3)
+- expression 5 operands: lhs = Counter(0), rhs = Counter(2)
 Number of file 0 mappings: 9
 - Code(Counter(0)) at (prev + 14, 1) to (start + 0, 11)
 - Code(Counter(1)) at (prev + 1, 9) to (start + 0, 12)
 - Code(Expression(0, Add)) at (prev + 0, 16) to (start + 0, 27)
     = (c0 + c1)
 - Code(Counter(1)) at (prev + 0, 28) to (start + 0, 40)
-- Code(Expression(8, Sub)) at (prev + 2, 8) to (start + 0, 37)
-    = ((c0 + c1) - c1)
+- Code(Counter(0)) at (prev + 2, 8) to (start + 0, 37)
 - Code(Counter(2)) at (prev + 0, 41) to (start + 0, 70)
 - Code(Counter(4)) at (prev + 0, 71) to (start + 2, 6)
-- Code(Expression(6, Add)) at (prev + 2, 6) to (start + 0, 7)
-    = ((((c0 + c1) - c1) - c2) + c3)
-- Code(Expression(5, Add)) at (prev + 2, 5) to (start + 1, 2)
-    = (c4 + ((((c0 + c1) - c1) - c2) + c3))
+- Code(Expression(4, Add)) at (prev + 2, 6) to (start + 0, 7)
+    = ((c0 - c2) + c3)
+- Code(Expression(3, Add)) at (prev + 2, 5) to (start + 1, 2)
+    = (c4 + ((c0 - c2) + c3))
 
 Function name: unicode::他 (unused)
 Raw bytes (9): 0x[01, 01, 00, 01, 00, 1e, 19, 00, 25]
diff --git a/tests/coverage/uses_inline_crate.cov-map b/tests/coverage/uses_inline_crate.cov-map
index 6b62182..55ceb46 100644
--- a/tests/coverage/uses_inline_crate.cov-map
+++ b/tests/coverage/uses_inline_crate.cov-map
@@ -7,19 +7,17 @@
 - Code(Counter(0)) at (prev + 44, 1) to (start + 2, 2)
 
 Function name: used_inline_crate::used_inline_function
-Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 14, 01, 06, 0f, 05, 06, 10, 02, 06, 02, 02, 06, 00, 07, 07, 01, 05, 01, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 14, 01, 06, 0f, 05, 06, 10, 02, 06, 02, 02, 06, 00, 07, 01, 01, 05, 01, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Counter(1)
-- expression 1 operands: lhs = Counter(1), rhs = Expression(0, Sub)
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 20, 1) to (start + 6, 15)
 - Code(Counter(1)) at (prev + 6, 16) to (start + 2, 6)
 - Code(Expression(0, Sub)) at (prev + 2, 6) to (start + 0, 7)
     = (c0 - c1)
-- Code(Expression(1, Add)) at (prev + 1, 5) to (start + 1, 2)
-    = (c1 + (c0 - c1))
+- Code(Counter(0)) at (prev + 1, 5) to (start + 1, 2)
 
 Function name: used_inline_crate::used_only_from_bin_crate_generic_function::<&alloc::vec::Vec<i32>>
 Raw bytes (9): 0x[01, 01, 00, 01, 01, 21, 01, 02, 02]
diff --git a/tests/coverage/while.cov-map b/tests/coverage/while.cov-map
index c6557b4..4d813a9 100644
--- a/tests/coverage/while.cov-map
+++ b/tests/coverage/while.cov-map
@@ -1,15 +1,13 @@
 Function name: while::main
-Raw bytes (28): 0x[01, 01, 02, 01, 00, 03, 00, 04, 01, 01, 01, 01, 10, 03, 02, 0b, 00, 14, 00, 00, 15, 02, 06, 06, 03, 01, 00, 02]
+Raw bytes (26): 0x[01, 01, 01, 01, 00, 04, 01, 01, 01, 01, 10, 03, 02, 0b, 00, 14, 00, 00, 15, 02, 06, 01, 03, 01, 00, 02]
 Number of files: 1
 - file 0 => global file 1
-Number of expressions: 2
+Number of expressions: 1
 - expression 0 operands: lhs = Counter(0), rhs = Zero
-- expression 1 operands: lhs = Expression(0, Add), rhs = Zero
 Number of file 0 mappings: 4
 - Code(Counter(0)) at (prev + 1, 1) to (start + 1, 16)
 - Code(Expression(0, Add)) at (prev + 2, 11) to (start + 0, 20)
     = (c0 + Zero)
 - Code(Zero) at (prev + 0, 21) to (start + 2, 6)
-- Code(Expression(1, Sub)) at (prev + 3, 1) to (start + 0, 2)
-    = ((c0 + Zero) - Zero)
+- Code(Counter(0)) at (prev + 3, 1) to (start + 0, 2)
 
diff --git a/tests/crashes/118185.rs b/tests/crashes/118185.rs
deleted file mode 100644
index c3a29c3..0000000
--- a/tests/crashes/118185.rs
+++ /dev/null
@@ -1,26 +0,0 @@
-//@ known-bug: #118185
-
-fn main() {
-    let target: Target = create_target();
-    target.get(0); // correct arguments work
-    target.get(10.0); // CRASH HERE
-}
-
-// must be generic
-fn create_target<T>() -> T {
-    unimplemented!()
-}
-
-// unimplemented trait, but contains function with the same name
-pub trait RandomTrait {
-    fn get(&mut self); // but less arguments
-}
-
-struct Target;
-
-impl Target {
-    // correct function with arguments
-    pub fn get(&self, data: i32) {
-        unimplemented!()
-    }
-}
diff --git a/tests/crashes/123901.rs b/tests/crashes/123901.rs
deleted file mode 100644
index 06722f0..0000000
--- a/tests/crashes/123901.rs
+++ /dev/null
@@ -1,8 +0,0 @@
-//@ known-bug: #123901
-//@ edition:2021
-
-pub fn test(test: &u64, temp: &u64) {
-    async |check, a, b| {
-        temp.abs_diff(12);
-    };
-}
diff --git a/tests/crashes/123911.rs b/tests/crashes/123911.rs
deleted file mode 100644
index 1a4d6a7..0000000
--- a/tests/crashes/123911.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//@ known-bug: #123911
-
-macro_rules! m {
-    ($attr_path: path) => {
-        #[$attr_path]
-        fn f() {}
-    }
-}
-
-m!(inline<{
-    let a = CharCharFloat { a: 1 };
-    let b = rustrt::rust_dbg_abi_4(a);
-    println!("a: {}", b.a);
-}>);
-
-fn main() {}
diff --git a/tests/crashes/123912.rs b/tests/crashes/123912.rs
deleted file mode 100644
index 35216ca..0000000
--- a/tests/crashes/123912.rs
+++ /dev/null
@@ -1,15 +0,0 @@
-//@ known-bug: #123912
-
-macro_rules! m {
-    ($attr_path: path) => {
-        #[$attr_path]
-        fn f() {}
-    }
-}
-
-m!(inline<{
-    let a = CharCharFloat { a: 1 };
-    println!("a: {}", a);
-}>);
-
-fn main() {}
diff --git a/tests/crashes/124436.rs b/tests/crashes/124436.rs
new file mode 100644
index 0000000..aed830e
--- /dev/null
+++ b/tests/crashes/124436.rs
@@ -0,0 +1,7 @@
+//@ known-bug: rust-lang/rust#124436
+//@ compile-flags: -Zdump-mir=all -Zpolymorphize=on
+
+pub trait TraitCat {}
+pub trait TraitDog {}
+
+pub fn gamma<T: TraitCat + TraitDog>(t: [TraitDog; 32]) {}
diff --git a/tests/crashes/124440.rs b/tests/crashes/124440.rs
new file mode 100644
index 0000000..431c4e4
--- /dev/null
+++ b/tests/crashes/124440.rs
@@ -0,0 +1,23 @@
+//@ known-bug: rust-lang/rust#124440
+
+#![allow(warnings)]
+
+trait Foo {}
+
+impl<F> Foo for F where F: FnMut(&()) {}
+
+struct Bar<F> {
+    f: F,
+}
+
+impl<F> Foo for Bar<F> where F: Foo {}
+
+fn assert_foo<F>(_: F)
+where
+    Bar<F>: Foo,
+{
+}
+
+fn main() {
+    assert_foo(|_| ());
+}
diff --git a/tests/crashes/124464.rs b/tests/crashes/124464.rs
new file mode 100644
index 0000000..471479f
--- /dev/null
+++ b/tests/crashes/124464.rs
@@ -0,0 +1,17 @@
+//@ known-bug: rust-lang/rust #124464
+enum TestOption<T> {
+    TestSome(T),
+    TestSome(T),
+}
+
+pub struct Request {
+    bar: TestOption<u64>,
+    bar: u8,
+}
+
+fn default_instance() -> &'static Request {
+    static instance: Request = Request { bar: 17 };
+    &instance
+}
+
+pub fn main() {}
diff --git a/tests/crashes/124490.rs b/tests/crashes/124490.rs
new file mode 100644
index 0000000..9f605c3
--- /dev/null
+++ b/tests/crashes/124490.rs
@@ -0,0 +1,16 @@
+//@ known-bug: rust-lang/rust#124490
+use io::{self as std};
+use std::collections::{self as io};
+
+mod a {
+    pub mod b {
+        pub mod c {}
+    }
+}
+
+use a::*;
+
+use b::c;
+use c as b;
+
+fn main() {}
diff --git a/tests/crashes/124552.rs b/tests/crashes/124552.rs
new file mode 100644
index 0000000..5320ce2
--- /dev/null
+++ b/tests/crashes/124552.rs
@@ -0,0 +1,12 @@
+//@ known-bug: rust-lang/rust#124552
+
+struct B;
+
+struct Foo {
+    b: u32,
+    b: B,
+}
+
+static BAR: Foo = Foo { b: B };
+
+fn main() {}
diff --git a/tests/crashes/124563.rs b/tests/crashes/124563.rs
new file mode 100644
index 0000000..b082739
--- /dev/null
+++ b/tests/crashes/124563.rs
@@ -0,0 +1,46 @@
+//@ known-bug: rust-lang/rust#124563
+
+use std::marker::PhantomData;
+
+pub trait Trait {}
+
+pub trait Foo {
+    type Trait: Trait;
+    type Bar: Bar;
+    fn foo(&mut self);
+}
+
+pub struct FooImpl<'a, 'b, A: Trait>(PhantomData<&'a &'b A>);
+
+impl<'a, 'b, T> Foo for FooImpl<'a, 'b, T>
+where
+    T: Trait,
+{
+    type Trait = T;
+    type Bar = BarImpl<'a, 'b, T>;
+
+    fn foo(&mut self) {
+        self.enter_scope(|ctx| {
+            BarImpl(ctx);
+        });
+    }
+}
+
+impl<'a, 'b, T> FooImpl<'a, 'b, T>
+where
+    T: Trait,
+{
+    fn enter_scope(&mut self, _scope: impl FnOnce(&mut Self)) {}
+}
+pub trait Bar {
+    type Foo: Foo;
+}
+
+pub struct BarImpl<'a, 'b, T: Trait>(&'b mut FooImpl<'a, 'b, T>);
+
+impl<'a, 'b, T> Bar for BarImpl<'a, 'b, T>
+where
+    T: Trait,
+{
+    type Foo = FooImpl<'a, 'b, T>;
+}
diff --git a/tests/crashes/124583.rs b/tests/crashes/124583.rs
new file mode 100644
index 0000000..ffd9d75
--- /dev/null
+++ b/tests/crashes/124583.rs
@@ -0,0 +1,5 @@
+//@ known-bug: rust-lang/rust#124583
+
+fn main() {
+    let _ = -(-0.0f16);
+}
diff --git a/tests/crashes/124751.rs b/tests/crashes/124751.rs
new file mode 100644
index 0000000..f15e399
--- /dev/null
+++ b/tests/crashes/124751.rs
@@ -0,0 +1,8 @@
+//@ known-bug: rust-lang/rust#124751
+//@ compile-flags: -Zunstable-options --edition=2024
+
+#![feature(gen_blocks)]
+
+fn main() {
+    let _ = async gen || {};
+}
diff --git a/tests/crashes/124833.rs b/tests/crashes/124833.rs
new file mode 100644
index 0000000..f1c4847
--- /dev/null
+++ b/tests/crashes/124833.rs
@@ -0,0 +1,10 @@
+//@ known-bug: rust-lang/rust#124833
+#![feature(generic_const_items)]
+
+trait Trait {
+    const C<'a>: &'a str;
+}
+
+impl Trait for () {
+    const C<'a>:  = "C";
+}
diff --git a/tests/crashes/124857.rs b/tests/crashes/124857.rs
new file mode 100644
index 0000000..4b952fd
--- /dev/null
+++ b/tests/crashes/124857.rs
@@ -0,0 +1,11 @@
+//@ known-bug: rust-lang/rust#124857
+//@ compile-flags: -Znext-solver=coherence
+
+#![feature(effects)]
+
+#[const_trait]
+trait Foo {}
+
+impl const Foo for i32 {}
+
+impl<T> const Foo for T where T: ~const Foo {}
diff --git a/tests/crashes/124891.rs b/tests/crashes/124891.rs
new file mode 100644
index 0000000..9b58924
--- /dev/null
+++ b/tests/crashes/124891.rs
@@ -0,0 +1,22 @@
+//@ known-bug: rust-lang/rust#124891
+
+type Tait = impl FnOnce() -> ();
+
+fn reify_as_tait() -> Thunk<Tait> {
+    Thunk::new(|cont| cont)
+}
+
+struct Thunk<F>(F);
+
+impl<F> Thunk<F> {
+    fn new(f: F)
+    where
+        F: ContFn,
+    {
+        todo!();
+    }
+}
+
+trait ContFn {}
+
+impl<F: FnOnce(Tait) -> ()> ContFn for F {}
diff --git a/tests/crashes/124894.rs b/tests/crashes/124894.rs
new file mode 100644
index 0000000..230cf4a
--- /dev/null
+++ b/tests/crashes/124894.rs
@@ -0,0 +1,11 @@
+//@ known-bug: rust-lang/rust#124894
+//@ compile-flags: -Znext-solver=coherence
+
+#![feature(generic_const_exprs)]
+
+pub trait IsTrue<const mem: bool> {}
+impl<T> IsZST for T where (): IsTrue<{ std::mem::size_of::<T>() == 0 }> {}
+
+pub trait IsZST {}
+
+impl IsZST for IsZST {}
diff --git a/tests/crashes/125081.rs b/tests/crashes/125081.rs
new file mode 100644
index 0000000..7139caa
--- /dev/null
+++ b/tests/crashes/125081.rs
@@ -0,0 +1,7 @@
+//@ known-bug: rust-lang/rust#125081
+
+use std::cell::Cell;
+
+fn main() {
+    let _: Cell<&str, "a"> = Cell::new('β);
+}
diff --git a/tests/crashes/125099.rs b/tests/crashes/125099.rs
new file mode 100644
index 0000000..bfc8c8f
--- /dev/null
+++ b/tests/crashes/125099.rs
@@ -0,0 +1,24 @@
+//@ known-bug: rust-lang/rust#125099
+
+pub trait ContFn<T>: Fn(T) -> Self::Future {
+    type Future;
+}
+impl<T, F> ContFn<T> for F
+where
+    F: Fn(T),
+{
+    type Future = ();
+}
+
+pub trait SeqHandler {
+    type Requires;
+    fn process<F: ContFn<Self::Requires>>() -> impl Sized;
+}
+
+pub struct ConvertToU64;
+impl SeqHandler for ConvertToU64 {
+    type Requires = u64;
+    fn process<F: ContFn<Self::Requires>>() -> impl Sized {}
+}
+
+fn main() {}
diff --git a/tests/crashes/125155.rs b/tests/crashes/125155.rs
new file mode 100644
index 0000000..165061d
--- /dev/null
+++ b/tests/crashes/125155.rs
@@ -0,0 +1,17 @@
+//@ known-bug: rust-lang/rust#125155
+
+enum NestedEnum {
+    First,
+    Second,
+    Third
+}
+enum Enum {
+    Variant2(Option<*mut &'a &'b ()>)
+}
+
+
+fn foo(x: Enum) -> isize {
+    match x {
+      Enum::Variant2(NestedEnum::Third) => 4,
+    }
+}
diff --git a/tests/crashes/125185.rs b/tests/crashes/125185.rs
new file mode 100644
index 0000000..8693d6c
--- /dev/null
+++ b/tests/crashes/125185.rs
@@ -0,0 +1,16 @@
+//@ known-bug: rust-lang/rust#125185
+//@ compile-flags: -Zvalidate-mir
+
+type Foo = impl Send;
+
+struct A;
+
+const VALUE: Foo = value();
+
+fn test(foo: Foo<'a>, f: impl for<'b> FnMut()) {
+    match VALUE {
+        0 | 0 => {}
+
+        _ => (),
+    }
+}
diff --git a/tests/crashes/125249.rs b/tests/crashes/125249.rs
new file mode 100644
index 0000000..18196d7
--- /dev/null
+++ b/tests/crashes/125249.rs
@@ -0,0 +1,8 @@
+//@ known-bug: rust-lang/rust#125185
+#![feature(return_position_impl_trait_in_trait, return_type_notation)]
+
+trait IntFactory {
+    fn stream(&self) -> impl IntFactory<stream(): IntFactory<stream(): Send> + Send>;
+}
+
+pub fn main() {}
diff --git a/tests/debuginfo/empty-string.rs b/tests/debuginfo/empty-string.rs
index 3624073..35b68ed 100644
--- a/tests/debuginfo/empty-string.rs
+++ b/tests/debuginfo/empty-string.rs
@@ -23,7 +23,7 @@
 // lldb-check:[...] empty_string = "" { vec = size=0 }
 
 // lldb-command:fr v empty_str
-// lldb-check:[...] empty_str = "" { data_ptr = [...] length = 0 }
+// lldb-check:[...] empty_str = ""
 
 fn main() {
     let empty_string = String::new();
diff --git a/tests/debuginfo/pretty-slices.rs b/tests/debuginfo/pretty-slices.rs
index 5d2086f..9defa34 100644
--- a/tests/debuginfo/pretty-slices.rs
+++ b/tests/debuginfo/pretty-slices.rs
@@ -27,10 +27,10 @@
 // lldb-check:(&mut [i32]) mut_slice = size=4 { [0] = 2 [1] = 3 [2] = 5 [3] = 7 }
 
 // lldb-command:v str_slice
-// lldb-check:(&str) str_slice = "string slice" { data_ptr = [...] length = 12 }
+// lldb-check:(&str) str_slice = "string slice" { [0] = 's' [1] = 't' [2] = 'r' [3] = 'i' [4] = 'n' [5] = 'g' [6] = ' ' [7] = 's' [8] = 'l' [9] = 'i' [10] = 'c' [11] = 'e' }
 
 // lldb-command:v mut_str_slice
-// lldb-check:(&mut str) mut_str_slice = "mutable string slice" { data_ptr = [...] length = 20 }
+// lldb-check:(&mut str) mut_str_slice = "mutable string slice" { [0] = 'm' [1] = 'u' [2] = 't' [3] = 'a' [4] = 'b' [5] = 'l' [6] = 'e' [7] = ' ' [8] = 's' [9] = 't' [10] = 'r' [11] = 'i' [12] = 'n' [13] = 'g' [14] = ' ' [15] = 's' [16] = 'l' [17] = 'i' [18] = 'c' [19] = 'e' }
 
 fn b() {}
 
diff --git a/tests/debuginfo/strings-and-strs.rs b/tests/debuginfo/strings-and-strs.rs
new file mode 100644
index 0000000..4a6adc2
--- /dev/null
+++ b/tests/debuginfo/strings-and-strs.rs
@@ -0,0 +1,63 @@
+//@ min-gdb-version: 14.0
+//@ min-lldb-version: 1800
+
+//@ compile-flags:-g
+
+// === GDB TESTS ===================================================================================
+// gdb-command:run
+
+// gdb-command:print plain_string
+// gdbr-check:$1 = alloc::string::String {vec: alloc::vec::Vec<u8, alloc::alloc::Global> {buf: alloc::raw_vec::RawVec<u8, alloc::alloc::Global> {ptr: core::ptr::unique::Unique<u8> {pointer: core::ptr::non_null::NonNull<u8> {pointer: 0x[...]}, _marker: core::marker::PhantomData<u8>}, cap: alloc::raw_vec::Cap (5), alloc: alloc::alloc::Global}, len: 5}}
+
+// gdb-command:print plain_str
+// gdbr-check:$2 = "Hello"
+
+// gdb-command:print str_in_struct
+// gdbr-check:$3 = strings_and_strs::Foo {inner: "Hello"}
+
+// gdb-command:print str_in_tuple
+// gdbr-check:$4 = ("Hello", "World")
+
+// gdb-command:print str_in_rc
+// gdbr-check:$5 = alloc::rc::Rc<&str, alloc::alloc::Global> {ptr: core::ptr::non_null::NonNull<alloc::rc::RcBox<&str>> {pointer: 0x[...]}, phantom: core::marker::PhantomData<alloc::rc::RcBox<&str>>, alloc: alloc::alloc::Global}
+
+
+// === LLDB TESTS ==================================================================================
+// lldb-command:run
+// lldb-command:v plain_string
+// lldbg-check:(alloc::string::String) plain_string = "Hello" { vec = size=5 { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } }
+
+// lldb-command:v plain_str
+// lldbg-check:(&str) plain_str = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' }
+
+// lldb-command:v str_in_struct
+// lldbg-check:((&str, &str)) str_in_tuple = { 0 = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } 1 = "World" { [0] = 'W' [1] = 'o' [2] = 'r' [3] = 'l' [4] = 'd' } }
+
+// lldb-command:v str_in_tuple
+// lldbg-check:((&str, &str)) str_in_tuple = { 0 = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } 1 = "World" { [0] = 'W' [1] = 'o' [2] = 'r' [3] = 'l' [4] = 'd' } }
+
+// lldb-command:v str_in_rc
+// lldbg-check:(alloc::rc::Rc<&str, alloc::alloc::Global>) str_in_rc = strong=1, weak=0 { value = "Hello" { [0] = 'H' [1] = 'e' [2] = 'l' [3] = 'l' [4] = 'o' } }
+
+
+#![allow(unused_variables)]
+#![feature(omit_gdb_pretty_printer_section)]
+#![omit_gdb_pretty_printer_section]
+
+pub struct Foo<'a> {
+    inner: &'a str,
+}
+
+fn main() {
+    let plain_string = String::from("Hello");
+    let plain_str = "Hello";
+    let str_in_struct = Foo { inner: "Hello" };
+    let str_in_tuple = ("Hello", "World");
+
+    let str_in_rc = std::rc::Rc::new("Hello");
+    zzz(); // #break
+}
+
+fn zzz() {
+    ()
+}
diff --git a/tests/incremental/foreign.rs b/tests/incremental/foreign.rs
index cb040fe..1af203e 100644
--- a/tests/incremental/foreign.rs
+++ b/tests/incremental/foreign.rs
@@ -1,38 +1,21 @@
 // Test what happens we save incremental compilation state that makes
 // use of foreign items. This used to ICE (#34991).
-//@ ignore-sgx no libc
-
 //@ revisions: rpass1
 
-#![feature(rustc_private)]
-
-extern crate libc;
-
 use std::ffi::CString;
 
 mod mlibc {
-    use libc::{c_char, c_long, c_longlong};
-
     extern "C" {
-        pub fn atol(x: *const c_char) -> c_long;
-        pub fn atoll(x: *const c_char) -> c_longlong;
+        // strlen is provided either by an external library or compiler-builtins as a fallback
+        pub fn strlen(x: *const std::ffi::c_char) -> usize;
     }
 }
 
-fn atol(s: String) -> isize {
+fn strlen(s: String) -> usize {
     let c = CString::new(s).unwrap();
-    unsafe { mlibc::atol(c.as_ptr()) as isize }
-}
-
-fn atoll(s: String) -> i64 {
-    let c = CString::new(s).unwrap();
-    unsafe { mlibc::atoll(c.as_ptr()) as i64 }
+    unsafe { mlibc::strlen(c.as_ptr()) }
 }
 
 pub fn main() {
-    assert_eq!(atol("1024".to_string()) * 10, atol("10240".to_string()));
-    assert_eq!(
-        (atoll("11111111111111111".to_string()) * 10),
-        atoll("111111111111111110".to_string())
-    );
+    assert_eq!(strlen("1024".to_string()), strlen("2048".to_string()));
 }
diff --git a/tests/mir-opt/building/custom/operators.f.built.after.mir b/tests/mir-opt/building/custom/operators.f.built.after.mir
index 33eb6b7..cac82f7 100644
--- a/tests/mir-opt/building/custom/operators.f.built.after.mir
+++ b/tests/mir-opt/building/custom/operators.f.built.after.mir
@@ -21,7 +21,7 @@
         _2 = Le(_1, _1);
         _2 = Ge(_1, _1);
         _2 = Gt(_1, _1);
-        _3 = CheckedAdd(_1, _1);
+        _3 = AddWithOverflow(_1, _1);
         _2 = (_3.1: bool);
         _1 = (_3.0: i32);
         _0 = _1;
diff --git a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff
index d5117b2..0e93c16 100644
--- a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-abort.diff
@@ -11,7 +11,7 @@
   
       bb0: {
           StorageLive(_1);
--         _2 = CheckedAdd(const 1_u32, const 1_u32);
+-         _2 = AddWithOverflow(const 1_u32, const 1_u32);
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> [success: bb1, unwind unreachable];
 +         _2 = const (2_u32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> [success: bb1, unwind unreachable];
diff --git a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff
index 2118d37..589eed5 100644
--- a/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/checked_add.main.GVN.panic-unwind.diff
@@ -11,7 +11,7 @@
   
       bb0: {
           StorageLive(_1);
--         _2 = CheckedAdd(const 1_u32, const 1_u32);
+-         _2 = AddWithOverflow(const 1_u32, const 1_u32);
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> [success: bb1, unwind continue];
 +         _2 = const (2_u32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> [success: bb1, unwind continue];
diff --git a/tests/mir-opt/const_prop/indirect.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/indirect.main.GVN.panic-abort.diff
index 8301a4c..f24b975 100644
--- a/tests/mir-opt/const_prop/indirect.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/indirect.main.GVN.panic-abort.diff
@@ -14,7 +14,7 @@
           StorageLive(_1);
           StorageLive(_2);
 -         _2 = const 2_u32 as u8 (IntToInt);
--         _3 = CheckedAdd(_2, const 1_u8);
+-         _3 = AddWithOverflow(_2, const 1_u8);
 -         assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> [success: bb1, unwind unreachable];
 +         _2 = const 2_u8;
 +         _3 = const (3_u8, false);
diff --git a/tests/mir-opt/const_prop/indirect.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/indirect.main.GVN.panic-unwind.diff
index 8dcbfd2..44ff313 100644
--- a/tests/mir-opt/const_prop/indirect.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/indirect.main.GVN.panic-unwind.diff
@@ -14,7 +14,7 @@
           StorageLive(_1);
           StorageLive(_2);
 -         _2 = const 2_u32 as u8 (IntToInt);
--         _3 = CheckedAdd(_2, const 1_u8);
+-         _3 = AddWithOverflow(_2, const 1_u8);
 -         assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> [success: bb1, unwind continue];
 +         _2 = const 2_u8;
 +         _3 = const (3_u8, false);
diff --git a/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-abort.diff b/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-abort.diff
index 8c5a0df..de9cb7a 100644
--- a/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-abort.diff
@@ -19,7 +19,7 @@
           StorageLive(_3);
           _3 = const 1_u8;
           StorageLive(_4);
--         _4 = CheckedAdd(_2, _3);
+-         _4 = AddWithOverflow(_2, _3);
 -         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind unreachable];
 +         _4 = const (0_u8, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind unreachable];
diff --git a/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-unwind.diff
index 7887a8a..1f19a13 100644
--- a/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/inherit_overflow.main.GVN.panic-unwind.diff
@@ -19,7 +19,7 @@
           StorageLive(_3);
           _3 = const 1_u8;
           StorageLive(_4);
--         _4 = CheckedAdd(_2, _3);
+-         _4 = AddWithOverflow(_2, _3);
 -         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind continue];
 +         _4 = const (0_u8, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind continue];
diff --git a/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff b/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff
index 51f8227..b2d40da 100644
--- a/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff
+++ b/tests/mir-opt/const_prop/return_place.add.GVN.panic-abort.diff
@@ -6,7 +6,7 @@
       let mut _1: (u32, bool);
   
       bb0: {
--         _1 = CheckedAdd(const 2_u32, const 2_u32);
+-         _1 = AddWithOverflow(const 2_u32, const 2_u32);
 -         assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> [success: bb1, unwind unreachable];
 +         _1 = const (4_u32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> [success: bb1, unwind unreachable];
diff --git a/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff b/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff
index 8174b4e..2eafc51 100644
--- a/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff
+++ b/tests/mir-opt/const_prop/return_place.add.GVN.panic-unwind.diff
@@ -6,7 +6,7 @@
       let mut _1: (u32, bool);
   
       bb0: {
--         _1 = CheckedAdd(const 2_u32, const 2_u32);
+-         _1 = AddWithOverflow(const 2_u32, const 2_u32);
 -         assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> [success: bb1, unwind continue];
 +         _1 = const (4_u32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> [success: bb1, unwind continue];
diff --git a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
index 3606a9e..01876b4 100644
--- a/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage.main.InstrumentCoverage.diff
@@ -8,12 +8,11 @@
       let mut _3: !;
   
 +     coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Add, rhs: Counter(1) };
-+     coverage ExpressionId(1) => Expression { lhs: Expression(0), op: Subtract, rhs: Counter(1) };
 +     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:10:1 - 10:11;
 +     coverage Code(Expression(0)) => $DIR/instrument_coverage.rs:11:5 - 12:17;
-+     coverage Code(Expression(1)) => $DIR/instrument_coverage.rs:13:13 - 13:18;
++     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:13:13 - 13:18;
 +     coverage Code(Counter(1)) => $DIR/instrument_coverage.rs:14:10 - 14:11;
-+     coverage Code(Expression(1)) => $DIR/instrument_coverage.rs:16:1 - 16:2;
++     coverage Code(Counter(0)) => $DIR/instrument_coverage.rs:16:1 - 16:2;
 + 
       bb0: {
 +         Coverage::CounterIncrement(0);
@@ -35,7 +34,6 @@
       }
   
       bb4: {
-+         Coverage::ExpressionUsed(1);
           _0 = const ();
           StorageDead(_2);
           return;
diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
index 34d0115..efb1559 100644
--- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
+++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.CleanupPostBorrowck.diff
@@ -8,11 +8,10 @@
       coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
   
       coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) };
-      coverage ExpressionId(1) => Expression { lhs: Counter(1), op: Add, rhs: Expression(0) };
       coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1 - 14:36;
       coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37 - 14:39;
       coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39 - 14:40;
-      coverage Code(Expression(1)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2;
+      coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2;
       coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36;
   
       bb0: {
@@ -44,7 +43,6 @@
       }
   
       bb4: {
-          Coverage::ExpressionUsed(1);
           StorageDead(_1);
           return;
       }
diff --git a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
index 6756d5c..a0fe9a5 100644
--- a/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
+++ b/tests/mir-opt/coverage/instrument_coverage_cleanup.main.InstrumentCoverage.diff
@@ -8,11 +8,10 @@
       coverage branch { true: BlockMarkerId(0), false: BlockMarkerId(1) } => $DIR/instrument_coverage_cleanup.rs:14:8: 14:36 (#0)
   
 +     coverage ExpressionId(0) => Expression { lhs: Counter(0), op: Subtract, rhs: Counter(1) };
-+     coverage ExpressionId(1) => Expression { lhs: Counter(1), op: Add, rhs: Expression(0) };
 +     coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:13:1 - 14:36;
 +     coverage Code(Expression(0)) => $DIR/instrument_coverage_cleanup.rs:14:37 - 14:39;
 +     coverage Code(Counter(1)) => $DIR/instrument_coverage_cleanup.rs:14:39 - 14:40;
-+     coverage Code(Expression(1)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2;
++     coverage Code(Counter(0)) => $DIR/instrument_coverage_cleanup.rs:15:1 - 15:2;
 +     coverage Branch { true_term: Expression(0), false_term: Counter(1) } => $DIR/instrument_coverage_cleanup.rs:14:8 - 14:36;
 + 
       bb0: {
@@ -41,7 +40,6 @@
       }
   
       bb4: {
-+         Coverage::ExpressionUsed(1);
           StorageDead(_1);
           return;
       }
diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
index b35538f..53663c6 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-abort.diff
@@ -40,7 +40,7 @@
 +         _4 = const 1_i32;
           StorageLive(_5);
 -         _5 = _2;
--         _6 = CheckedAdd(_4, _5);
+-         _6 = AddWithOverflow(_4, _5);
 -         assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, move _5) -> [success: bb1, unwind unreachable];
 +         _5 = const 2_i32;
 +         _6 = const (3_i32, false);
@@ -57,7 +57,7 @@
           StorageLive(_8);
           StorageLive(_9);
 -         _9 = _7;
--         _10 = CheckedAdd(_9, const 1_i32);
+-         _10 = AddWithOverflow(_9, const 1_i32);
 -         assert(!move (_10.1: bool), "attempt to compute `{} + {}`, which would overflow", move _9, const 1_i32) -> [success: bb2, unwind unreachable];
 +         _9 = const i32::MAX;
 +         _10 = const (i32::MIN, true);
diff --git a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
index 05c9696..34feb2a 100644
--- a/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/checked.main.DataflowConstProp.panic-unwind.diff
@@ -40,7 +40,7 @@
 +         _4 = const 1_i32;
           StorageLive(_5);
 -         _5 = _2;
--         _6 = CheckedAdd(_4, _5);
+-         _6 = AddWithOverflow(_4, _5);
 -         assert(!move (_6.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, move _5) -> [success: bb1, unwind continue];
 +         _5 = const 2_i32;
 +         _6 = const (3_i32, false);
@@ -57,7 +57,7 @@
           StorageLive(_8);
           StorageLive(_9);
 -         _9 = _7;
--         _10 = CheckedAdd(_9, const 1_i32);
+-         _10 = AddWithOverflow(_9, const 1_i32);
 -         assert(!move (_10.1: bool), "attempt to compute `{} + {}`, which would overflow", move _9, const 1_i32) -> [success: bb2, unwind continue];
 +         _9 = const i32::MAX;
 +         _10 = const (i32::MIN, true);
diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff
index ca1bd73..8d62de0 100644
--- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff
+++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-abort.diff
@@ -19,7 +19,7 @@
           StorageLive(_3);
           _3 = const 1_u8;
           StorageLive(_4);
--         _4 = CheckedAdd(_2, _3);
+-         _4 = AddWithOverflow(_2, _3);
 -         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind unreachable];
 +         _4 = const (0_u8, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind unreachable];
diff --git a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
index 0d7fe93..2562485 100644
--- a/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
+++ b/tests/mir-opt/dataflow-const-prop/inherit_overflow.main.DataflowConstProp.panic-unwind.diff
@@ -19,7 +19,7 @@
           StorageLive(_3);
           _3 = const 1_u8;
           StorageLive(_4);
--         _4 = CheckedAdd(_2, _3);
+-         _4 = AddWithOverflow(_2, _3);
 -         assert(!move (_4.1: bool), "attempt to compute `{} + {}`, which would overflow", _2, _3) -> [success: bb1, unwind continue];
 +         _4 = const (0_u8, true);
 +         assert(!const true, "attempt to compute `{} + {}`, which would overflow", const u8::MAX, const 1_u8) -> [success: bb1, unwind continue];
diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
index a45d992..5bf22af 100644
--- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-abort.diff
@@ -31,9 +31,9 @@
           StorageLive(_3);
           StorageLive(_4);
           _4 = _1;
--         _5 = CheckedAdd(_4, const 0_u64);
+-         _5 = AddWithOverflow(_4, const 0_u64);
 -         assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, const 0_u64) -> [success: bb1, unwind unreachable];
-+         _5 = CheckedAdd(_1, const 0_u64);
++         _5 = AddWithOverflow(_1, const 0_u64);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind unreachable];
       }
   
@@ -52,7 +52,7 @@
           StorageLive(_7);
           StorageLive(_8);
           _8 = _1;
--         _9 = CheckedSub(_8, const 0_u64);
+-         _9 = SubWithOverflow(_8, const 0_u64);
 -         assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", move _8, const 0_u64) -> [success: bb3, unwind unreachable];
 +         _9 = _5;
 +         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind unreachable];
@@ -76,7 +76,7 @@
           _12 = _1;
           StorageLive(_13);
           _13 = _1;
--         _14 = CheckedSub(_12, _13);
+-         _14 = SubWithOverflow(_12, _13);
 -         assert(!move (_14.1: bool), "attempt to compute `{} - {}`, which would overflow", move _12, move _13) -> [success: bb5, unwind unreachable];
 +         _14 = const (0_u64, false);
 +         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, _1) -> [success: bb5, unwind unreachable];
@@ -99,7 +99,7 @@
           StorageLive(_16);
           StorageLive(_17);
           _17 = _1;
--         _18 = CheckedMul(_17, const 0_u64);
+-         _18 = MulWithOverflow(_17, const 0_u64);
 -         assert(!move (_18.1: bool), "attempt to compute `{} * {}`, which would overflow", move _17, const 0_u64) -> [success: bb7, unwind unreachable];
 +         _18 = const (0_u64, false);
 +         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb7, unwind unreachable];
@@ -120,7 +120,7 @@
           StorageLive(_20);
           StorageLive(_21);
           _21 = _1;
--         _22 = CheckedMul(_21, const 1_u64);
+-         _22 = MulWithOverflow(_21, const 1_u64);
 -         assert(!move (_22.1: bool), "attempt to compute `{} * {}`, which would overflow", move _21, const 1_u64) -> [success: bb9, unwind unreachable];
 +         _22 = _5;
 +         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb9, unwind unreachable];
diff --git a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
index 9033b39..18d2029 100644
--- a/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.arithmetic_checked.GVN.panic-unwind.diff
@@ -31,9 +31,9 @@
           StorageLive(_3);
           StorageLive(_4);
           _4 = _1;
--         _5 = CheckedAdd(_4, const 0_u64);
+-         _5 = AddWithOverflow(_4, const 0_u64);
 -         assert(!move (_5.1: bool), "attempt to compute `{} + {}`, which would overflow", move _4, const 0_u64) -> [success: bb1, unwind continue];
-+         _5 = CheckedAdd(_1, const 0_u64);
++         _5 = AddWithOverflow(_1, const 0_u64);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", _1, const 0_u64) -> [success: bb1, unwind continue];
       }
   
@@ -52,7 +52,7 @@
           StorageLive(_7);
           StorageLive(_8);
           _8 = _1;
--         _9 = CheckedSub(_8, const 0_u64);
+-         _9 = SubWithOverflow(_8, const 0_u64);
 -         assert(!move (_9.1: bool), "attempt to compute `{} - {}`, which would overflow", move _8, const 0_u64) -> [success: bb3, unwind continue];
 +         _9 = _5;
 +         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, const 0_u64) -> [success: bb3, unwind continue];
@@ -76,7 +76,7 @@
           _12 = _1;
           StorageLive(_13);
           _13 = _1;
--         _14 = CheckedSub(_12, _13);
+-         _14 = SubWithOverflow(_12, _13);
 -         assert(!move (_14.1: bool), "attempt to compute `{} - {}`, which would overflow", move _12, move _13) -> [success: bb5, unwind continue];
 +         _14 = const (0_u64, false);
 +         assert(!const false, "attempt to compute `{} - {}`, which would overflow", _1, _1) -> [success: bb5, unwind continue];
@@ -99,7 +99,7 @@
           StorageLive(_16);
           StorageLive(_17);
           _17 = _1;
--         _18 = CheckedMul(_17, const 0_u64);
+-         _18 = MulWithOverflow(_17, const 0_u64);
 -         assert(!move (_18.1: bool), "attempt to compute `{} * {}`, which would overflow", move _17, const 0_u64) -> [success: bb7, unwind continue];
 +         _18 = const (0_u64, false);
 +         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 0_u64) -> [success: bb7, unwind continue];
@@ -120,7 +120,7 @@
           StorageLive(_20);
           StorageLive(_21);
           _21 = _1;
--         _22 = CheckedMul(_21, const 1_u64);
+-         _22 = MulWithOverflow(_21, const 1_u64);
 -         assert(!move (_22.1: bool), "attempt to compute `{} * {}`, which would overflow", move _21, const 1_u64) -> [success: bb9, unwind continue];
 +         _22 = _5;
 +         assert(!const false, "attempt to compute `{} * {}`, which would overflow", _1, const 1_u64) -> [success: bb9, unwind continue];
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
index 68cb4d5..25d0e5c 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-abort.diff
@@ -69,9 +69,9 @@
 +         nop;
           StorageLive(_9);
 -         _9 = _7;
--         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+-         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
 +         _9 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -87,9 +87,9 @@
 +         nop;
           StorageLive(_13);
 -         _13 = _7;
--         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+-         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
 +         _13 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
index fa18434..3c5fd94 100644
--- a/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
+++ b/tests/mir-opt/gvn.fn_pointers.GVN.panic-unwind.diff
@@ -69,9 +69,9 @@
 +         nop;
           StorageLive(_9);
 -         _9 = _7;
--         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+-         _8 = move _9 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
 +         _9 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
-+         _8 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _8 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
           StorageDead(_9);
           StorageLive(_10);
           StorageLive(_11);
@@ -87,9 +87,9 @@
 +         nop;
           StorageLive(_13);
 -         _13 = _7;
--         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Normal)));
+-         _12 = move _13 as fn() (PointerCoercion(ClosureFnPointer(Safe)));
 +         _13 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21};
-+         _12 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Normal)));
++         _12 = const ZeroSized: {closure@$DIR/gvn.rs:612:19: 612:21} as fn() (PointerCoercion(ClosureFnPointer(Safe)));
           StorageDead(_13);
           StorageLive(_14);
           StorageLive(_15);
diff --git a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
index 2a36cca..df87360 100644
--- a/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
+++ b/tests/mir-opt/inline/inline_shims.drop.Inline.panic-abort.diff
@@ -11,10 +11,28 @@
 +     scope 1 (inlined std::ptr::drop_in_place::<Vec<A>> - shim(Some(Vec<A>))) {
 +         let mut _6: &mut std::vec::Vec<A>;
 +         let mut _7: ();
++         scope 2 (inlined <Vec<A> as Drop>::drop) {
++             let mut _8: *mut [A];
++             let mut _9: *mut A;
++             let mut _10: usize;
++             scope 3 (inlined Vec::<A>::as_mut_ptr) {
++                 let mut _11: &alloc::raw_vec::RawVec<A>;
++                 scope 4 (inlined alloc::raw_vec::RawVec::<A>::ptr) {
++                     let mut _13: std::ptr::NonNull<A>;
++                     scope 5 (inlined Unique::<A>::as_ptr) {
++                         scope 6 (inlined NonNull::<A>::as_ptr) {
++                             let mut _12: *const A;
++                         }
++                     }
++                 }
++             }
++             scope 7 (inlined slice_from_raw_parts_mut::<A>) {
++             }
++         }
 +     }
-+     scope 2 (inlined std::ptr::drop_in_place::<Option<B>> - shim(Some(Option<B>))) {
-+         let mut _8: isize;
-+         let mut _9: isize;
++     scope 8 (inlined std::ptr::drop_in_place::<Option<B>> - shim(Some(Option<B>))) {
++         let mut _14: isize;
++         let mut _15: isize;
 +     }
   
       bb0: {
@@ -25,7 +43,24 @@
 +         StorageLive(_6);
 +         StorageLive(_7);
 +         _6 = &mut (*_4);
-+         _7 = <Vec<A> as Drop>::drop(move _6) -> [return: bb2, unwind unreachable];
++         StorageLive(_8);
++         StorageLive(_9);
++         StorageLive(_11);
++         _11 = &((*_6).0: alloc::raw_vec::RawVec<A>);
++         StorageLive(_13);
++         _13 = ((((*_6).0: alloc::raw_vec::RawVec<A>).0: std::ptr::Unique<A>).0: std::ptr::NonNull<A>);
++         StorageLive(_12);
++         _12 = (_13.0: *const A);
++         _9 = move _12 as *mut A (PtrToPtr);
++         StorageDead(_12);
++         StorageDead(_13);
++         StorageDead(_11);
++         StorageLive(_10);
++         _10 = ((*_6).1: usize);
++         _8 = *mut [A] from (_9, _10);
++         StorageDead(_10);
++         StorageDead(_9);
++         _7 = std::ptr::drop_in_place::<[A]>(move _8) -> [return: bb2, unwind unreachable];
       }
   
       bb1: {
@@ -36,19 +71,20 @@
           StorageLive(_5);
           _5 = _2;
 -         _0 = std::ptr::drop_in_place::<Option<B>>(move _5) -> [return: bb2, unwind unreachable];
-+         StorageLive(_8);
-+         StorageLive(_9);
-+         _8 = discriminant((*_5));
-+         switchInt(move _8) -> [0: bb3, otherwise: bb4];
++         StorageLive(_14);
++         StorageLive(_15);
++         _14 = discriminant((*_5));
++         switchInt(move _14) -> [0: bb3, otherwise: bb4];
       }
   
       bb2: {
++         StorageDead(_8);
 +         drop(((*_4).0: alloc::raw_vec::RawVec<A>)) -> [return: bb1, unwind unreachable];
 +     }
 + 
 +     bb3: {
-+         StorageDead(_9);
-+         StorageDead(_8);
++         StorageDead(_15);
++         StorageDead(_14);
           StorageDead(_5);
           return;
 +     }
diff --git "a/tests/mir-opt/issue_41697.\173impl\0430\175-\173constant\0430\175.SimplifyCfg-promote-consts.after.mir" "b/tests/mir-opt/issue_41697.\173impl\0430\175-\173constant\0430\175.SimplifyCfg-promote-consts.after.mir"
index 7dafeab..7d2e97f 100644
--- "a/tests/mir-opt/issue_41697.\173impl\0430\175-\173constant\0430\175.SimplifyCfg-promote-consts.after.mir"
+++ "b/tests/mir-opt/issue_41697.\173impl\0430\175-\173constant\0430\175.SimplifyCfg-promote-consts.after.mir"
@@ -5,7 +5,7 @@
     let mut _1: (usize, bool);
 
     bb0: {
-        _1 = CheckedAdd(const 1_usize, const 1_usize);
+        _1 = AddWithOverflow(const 1_usize, const 1_usize);
         assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb1, unwind: bb2];
     }
 
diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs
index 12e526a..180bfd0 100644
--- a/tests/mir-opt/lower_intrinsics.rs
+++ b/tests/mir-opt/lower_intrinsics.rs
@@ -184,9 +184,9 @@
 // EMIT_MIR lower_intrinsics.with_overflow.LowerIntrinsics.diff
 pub fn with_overflow(a: i32, b: i32) {
     // CHECK-LABEL: fn with_overflow(
-    // CHECK: CheckedAdd(
-    // CHECK: CheckedSub(
-    // CHECK: CheckedMul(
+    // CHECK: AddWithOverflow(
+    // CHECK: SubWithOverflow(
+    // CHECK: MulWithOverflow(
 
     let _x = core::intrinsics::add_with_overflow(a, b);
     let _y = core::intrinsics::sub_with_overflow(a, b);
diff --git a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-abort.diff
index da84449..efbbeeeac 100644
--- a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-abort.diff
+++ b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-abort.diff
@@ -31,7 +31,7 @@
           StorageLive(_5);
           _5 = _2;
 -         _3 = add_with_overflow::<i32>(move _4, move _5) -> [return: bb1, unwind unreachable];
-+         _3 = CheckedAdd(move _4, move _5);
++         _3 = AddWithOverflow(move _4, move _5);
 +         goto -> bb1;
       }
   
@@ -44,7 +44,7 @@
           StorageLive(_8);
           _8 = _2;
 -         _6 = sub_with_overflow::<i32>(move _7, move _8) -> [return: bb2, unwind unreachable];
-+         _6 = CheckedSub(move _7, move _8);
++         _6 = SubWithOverflow(move _7, move _8);
 +         goto -> bb2;
       }
   
@@ -57,7 +57,7 @@
           StorageLive(_11);
           _11 = _2;
 -         _9 = mul_with_overflow::<i32>(move _10, move _11) -> [return: bb3, unwind unreachable];
-+         _9 = CheckedMul(move _10, move _11);
++         _9 = MulWithOverflow(move _10, move _11);
 +         goto -> bb3;
       }
   
diff --git a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-unwind.diff
index da84449..efbbeeeac 100644
--- a/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-unwind.diff
+++ b/tests/mir-opt/lower_intrinsics.with_overflow.LowerIntrinsics.panic-unwind.diff
@@ -31,7 +31,7 @@
           StorageLive(_5);
           _5 = _2;
 -         _3 = add_with_overflow::<i32>(move _4, move _5) -> [return: bb1, unwind unreachable];
-+         _3 = CheckedAdd(move _4, move _5);
++         _3 = AddWithOverflow(move _4, move _5);
 +         goto -> bb1;
       }
   
@@ -44,7 +44,7 @@
           StorageLive(_8);
           _8 = _2;
 -         _6 = sub_with_overflow::<i32>(move _7, move _8) -> [return: bb2, unwind unreachable];
-+         _6 = CheckedSub(move _7, move _8);
++         _6 = SubWithOverflow(move _7, move _8);
 +         goto -> bb2;
       }
   
@@ -57,7 +57,7 @@
           StorageLive(_11);
           _11 = _2;
 -         _9 = mul_with_overflow::<i32>(move _10, move _11) -> [return: bb3, unwind unreachable];
-+         _9 = CheckedMul(move _10, move _11);
++         _9 = MulWithOverflow(move _10, move _11);
 +         goto -> bb3;
       }
   
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff
index 0e7e1f9..2f34a62 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-abort.diff
@@ -24,7 +24,7 @@
   
       bb0: {
           StorageLive(_1);
--         _2 = CheckedAdd(const 2_i32, const 2_i32);
+-         _2 = AddWithOverflow(const 2_i32, const 2_i32);
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind unreachable];
 +         _2 = const (4_i32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind unreachable];
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff
index 9071a33..da7add3 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.32bit.panic-unwind.diff
@@ -24,7 +24,7 @@
   
       bb0: {
           StorageLive(_1);
--         _2 = CheckedAdd(const 2_i32, const 2_i32);
+-         _2 = AddWithOverflow(const 2_i32, const 2_i32);
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
 +         _2 = const (4_i32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff
index 0e7e1f9..2f34a62 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-abort.diff
@@ -24,7 +24,7 @@
   
       bb0: {
           StorageLive(_1);
--         _2 = CheckedAdd(const 2_i32, const 2_i32);
+-         _2 = AddWithOverflow(const 2_i32, const 2_i32);
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind unreachable];
 +         _2 = const (4_i32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind unreachable];
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff
index 9071a33..da7add3 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.GVN.64bit.panic-unwind.diff
@@ -24,7 +24,7 @@
   
       bb0: {
           StorageLive(_1);
--         _2 = CheckedAdd(const 2_i32, const 2_i32);
+-         _2 = AddWithOverflow(const 2_i32, const 2_i32);
 -         assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
 +         _2 = const (4_i32, false);
 +         assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff
index 5f2a096..802bfbb 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-abort.diff
@@ -26,7 +26,7 @@
   
       bb0: {
           StorageLive(_1);
-          _2 = CheckedAdd(const 2_i32, const 2_i32);
+          _2 = AddWithOverflow(const 2_i32, const 2_i32);
           assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff
index a49546f..de94a55 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.32bit.panic-unwind.diff
@@ -26,7 +26,7 @@
   
       bb0: {
           StorageLive(_1);
-          _2 = CheckedAdd(const 2_i32, const 2_i32);
+          _2 = AddWithOverflow(const 2_i32, const 2_i32);
           assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff
index 5f2a096..802bfbb 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-abort.diff
@@ -26,7 +26,7 @@
   
       bb0: {
           StorageLive(_1);
-          _2 = CheckedAdd(const 2_i32, const 2_i32);
+          _2 = AddWithOverflow(const 2_i32, const 2_i32);
           assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind unreachable];
       }
   
diff --git a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff
index a49546f..de94a55 100644
--- a/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff
+++ b/tests/mir-opt/pre-codegen/optimizes_into_variable.main.ScalarReplacementOfAggregates.64bit.panic-unwind.diff
@@ -26,7 +26,7 @@
   
       bb0: {
           StorageLive(_1);
-          _2 = CheckedAdd(const 2_i32, const 2_i32);
+          _2 = AddWithOverflow(const 2_i32, const 2_i32);
           assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> [success: bb1, unwind continue];
       }
   
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
index ef3f4a2..62fe1a8 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir
@@ -4,20 +4,47 @@
     debug slice => _1;
     debug index => _2;
     let mut _0: &mut [u32];
+    let mut _3: usize;
+    let mut _4: usize;
     scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) {
-        let mut _3: *mut [u32];
-        let mut _4: *mut [u32];
+        let mut _5: *mut [u32];
+        let mut _9: *mut [u32];
+        scope 2 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) {
+            let _6: usize;
+            let mut _7: *mut u32;
+            let mut _8: *mut u32;
+            scope 3 {
+                scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) {
+                }
+                scope 7 (inlined std::ptr::mut_ptr::<impl *mut u32>::add) {
+                }
+                scope 8 (inlined slice_from_raw_parts_mut::<u32>) {
+                }
+            }
+            scope 4 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) {
+                scope 5 (inlined std::ptr::metadata::<[u32]>) {
+                }
+            }
+        }
     }
 
     bb0: {
-        StorageLive(_3);
-        _3 = &raw mut (*_1);
-        _4 = <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut(move _2, move _3) -> [return: bb1, unwind unreachable];
-    }
-
-    bb1: {
-        StorageDead(_3);
-        _0 = &mut (*_4);
+        _3 = move (_2.0: usize);
+        _4 = move (_2.1: usize);
+        StorageLive(_5);
+        _5 = &raw mut (*_1);
+        StorageLive(_6);
+        _6 = SubUnchecked(_4, _3);
+        StorageLive(_8);
+        StorageLive(_7);
+        _7 = _5 as *mut u32 (PtrToPtr);
+        _8 = Offset(_7, _3);
+        StorageDead(_7);
+        _9 = *mut [u32] from (_8, _6);
+        StorageDead(_8);
+        StorageDead(_6);
+        StorageDead(_5);
+        _0 = &mut (*_9);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
index 9e93a43..62fe1a8 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir
@@ -4,20 +4,47 @@
     debug slice => _1;
     debug index => _2;
     let mut _0: &mut [u32];
+    let mut _3: usize;
+    let mut _4: usize;
     scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) {
-        let mut _3: *mut [u32];
-        let mut _4: *mut [u32];
+        let mut _5: *mut [u32];
+        let mut _9: *mut [u32];
+        scope 2 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) {
+            let _6: usize;
+            let mut _7: *mut u32;
+            let mut _8: *mut u32;
+            scope 3 {
+                scope 6 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) {
+                }
+                scope 7 (inlined std::ptr::mut_ptr::<impl *mut u32>::add) {
+                }
+                scope 8 (inlined slice_from_raw_parts_mut::<u32>) {
+                }
+            }
+            scope 4 (inlined std::ptr::mut_ptr::<impl *mut [u32]>::len) {
+                scope 5 (inlined std::ptr::metadata::<[u32]>) {
+                }
+            }
+        }
     }
 
     bb0: {
-        StorageLive(_3);
-        _3 = &raw mut (*_1);
-        _4 = <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut(move _2, move _3) -> [return: bb1, unwind continue];
-    }
-
-    bb1: {
-        StorageDead(_3);
-        _0 = &mut (*_4);
+        _3 = move (_2.0: usize);
+        _4 = move (_2.1: usize);
+        StorageLive(_5);
+        _5 = &raw mut (*_1);
+        StorageLive(_6);
+        _6 = SubUnchecked(_4, _3);
+        StorageLive(_8);
+        StorageLive(_7);
+        _7 = _5 as *mut u32 (PtrToPtr);
+        _8 = Offset(_7, _3);
+        StorageDead(_7);
+        _9 = *mut [u32] from (_8, _6);
+        StorageDead(_8);
+        StorageDead(_6);
+        StorageDead(_5);
+        _0 = &mut (*_9);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir
index 018ff6c..000432c 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-abort.mir
@@ -17,11 +17,6 @@
                 scope 7 (inlined std::ptr::const_ptr::<impl *const u32>::add) {
                 }
                 scope 8 (inlined slice_from_raw_parts::<u32>) {
-                    let mut _8: *const ();
-                    scope 9 (inlined std::ptr::const_ptr::<impl *const u32>::cast::<()>) {
-                    }
-                    scope 10 (inlined std::ptr::from_raw_parts::<[u32]>) {
-                    }
                 }
             }
             scope 4 (inlined std::ptr::const_ptr::<impl *const [u32]>::len) {
@@ -41,10 +36,7 @@
         _6 = _1 as *const u32 (PtrToPtr);
         _7 = Offset(_6, _3);
         StorageDead(_6);
-        StorageLive(_8);
-        _8 = _7 as *const () (PtrToPtr);
-        _0 = *const [u32] from (_8, _5);
-        StorageDead(_8);
+        _0 = *const [u32] from (_7, _5);
         StorageDead(_7);
         StorageDead(_5);
         return;
diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir
index 018ff6c..000432c 100644
--- a/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/slice_index.slice_ptr_get_unchecked_range.PreCodegen.after.panic-unwind.mir
@@ -17,11 +17,6 @@
                 scope 7 (inlined std::ptr::const_ptr::<impl *const u32>::add) {
                 }
                 scope 8 (inlined slice_from_raw_parts::<u32>) {
-                    let mut _8: *const ();
-                    scope 9 (inlined std::ptr::const_ptr::<impl *const u32>::cast::<()>) {
-                    }
-                    scope 10 (inlined std::ptr::from_raw_parts::<[u32]>) {
-                    }
                 }
             }
             scope 4 (inlined std::ptr::const_ptr::<impl *const [u32]>::len) {
@@ -41,10 +36,7 @@
         _6 = _1 as *const u32 (PtrToPtr);
         _7 = Offset(_6, _3);
         StorageDead(_6);
-        StorageLive(_8);
-        _8 = _7 as *const () (PtrToPtr);
-        _0 = *const [u32] from (_8, _5);
-        StorageDead(_8);
+        _0 = *const [u32] from (_7, _5);
         StorageDead(_7);
         StorageDead(_5);
         return;
diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir
index 18728d5..eabecae 100644
--- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir
+++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-abort.mir
@@ -25,7 +25,7 @@
         scope 6 (inlined std::slice::from_raw_parts::<'_, u8>) {
             debug data => _4;
             debug len => _5;
-            let _7: *const [u8];
+            let _6: *const [u8];
             scope 7 (inlined core::ub_checks::check_language_ub) {
                 scope 8 (inlined core::ub_checks::check_language_ub::runtime) {
                 }
@@ -37,14 +37,6 @@
             scope 11 (inlined slice_from_raw_parts::<u8>) {
                 debug data => _4;
                 debug len => _5;
-                let mut _6: *const ();
-                scope 12 (inlined std::ptr::const_ptr::<impl *const u8>::cast::<()>) {
-                    debug self => _4;
-                }
-                scope 13 (inlined std::ptr::from_raw_parts::<[u8]>) {
-                    debug data_pointer => _6;
-                    debug metadata => _5;
-                }
             }
         }
     }
@@ -60,13 +52,10 @@
         StorageDead(_2);
         StorageLive(_5);
         _5 = ((*_1).1: usize);
-        StorageLive(_6);
-        _6 = _4 as *const () (PtrToPtr);
-        _7 = *const [u8] from (_6, _5);
-        StorageDead(_6);
+        _6 = *const [u8] from (_4, _5);
         StorageDead(_5);
         StorageDead(_4);
-        _0 = &(*_7);
+        _0 = &(*_6);
         return;
     }
 }
diff --git a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir
index 18728d5..eabecae 100644
--- a/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir
+++ b/tests/mir-opt/pre-codegen/vec_deref.vec_deref_to_slice.PreCodegen.after.panic-unwind.mir
@@ -25,7 +25,7 @@
         scope 6 (inlined std::slice::from_raw_parts::<'_, u8>) {
             debug data => _4;
             debug len => _5;
-            let _7: *const [u8];
+            let _6: *const [u8];
             scope 7 (inlined core::ub_checks::check_language_ub) {
                 scope 8 (inlined core::ub_checks::check_language_ub::runtime) {
                 }
@@ -37,14 +37,6 @@
             scope 11 (inlined slice_from_raw_parts::<u8>) {
                 debug data => _4;
                 debug len => _5;
-                let mut _6: *const ();
-                scope 12 (inlined std::ptr::const_ptr::<impl *const u8>::cast::<()>) {
-                    debug self => _4;
-                }
-                scope 13 (inlined std::ptr::from_raw_parts::<[u8]>) {
-                    debug data_pointer => _6;
-                    debug metadata => _5;
-                }
             }
         }
     }
@@ -60,13 +52,10 @@
         StorageDead(_2);
         StorageLive(_5);
         _5 = ((*_1).1: usize);
-        StorageLive(_6);
-        _6 = _4 as *const () (PtrToPtr);
-        _7 = *const [u8] from (_6, _5);
-        StorageDead(_6);
+        _6 = *const [u8] from (_4, _5);
         StorageDead(_5);
         StorageDead(_4);
-        _0 = &(*_7);
+        _0 = &(*_6);
         return;
     }
 }
diff --git a/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir b/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
index d7372a0..a35af43 100644
--- a/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
+++ b/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-abort.mir
@@ -105,7 +105,7 @@
         StorageLive(_14);
         _14 = {closure@main::{closure#0}};
         Retag(_14);
-        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
+        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Safe)));
         StorageDead(_14);
         StorageLive(_15);
         StorageLive(_16);
diff --git a/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir b/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
index 6ec62bf..2495719 100644
--- a/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
+++ b/tests/mir-opt/retag.main.SimplifyCfg-pre-optimizations.after.panic-unwind.mir
@@ -105,7 +105,7 @@
         StorageLive(_14);
         _14 = {closure@main::{closure#0}};
         Retag(_14);
-        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Normal)));
+        _13 = move _14 as for<'a> fn(&'a i32) -> &'a i32 (PointerCoercion(ClosureFnPointer(Safe)));
         StorageDead(_14);
         StorageLive(_15);
         StorageLive(_16);
diff --git a/tests/pretty/issue-4264.pp b/tests/pretty/issue-4264.pp
index af64260..4d43db5 100644
--- a/tests/pretty/issue-4264.pp
+++ b/tests/pretty/issue-4264.pp
@@ -11,15 +11,15 @@
 fn foo(_: [i32; (3 as usize)]) ({ } as ())
 
 fn bar() ({
-        const FOO: usize = ((5 as usize) - (4 as usize) as usize);
-        let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]);
+    const FOO: usize = ((5 as usize) - (4 as usize) as usize);
+    let _: [(); (FOO as usize)] = ([(() as ())] as [(); 1]);
 
-        let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]);
+    let _: [(); (1 as usize)] = ([(() as ())] as [(); 1]);
 
-        let _ =
-            (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as
-                        &[i32; 3]) as *const _ as *const [i32; 3]) as
-                *const [i32; (3 as usize)] as *const [i32; 3]);
+    let _ =
+        (((&([(1 as i32), (2 as i32), (3 as i32)] as [i32; 3]) as &[i32; 3])
+                as *const _ as *const [i32; 3]) as *const [i32; (3 as usize)]
+            as *const [i32; 3]);
 
 
 
@@ -29,17 +29,17 @@
 
 
 
-        ({
-                let res =
-                    ((::alloc::fmt::format as
-                            for<'a> fn(Arguments<'a>) -> String {format})(((format_arguments::new_const
-                                as
-                                fn(&[&'static str]) -> Arguments<'_> {Arguments::<'_>::new_const})((&([("test"
-                                            as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>))
-                        as String);
-                (res as String)
-            } as String);
-    } as ())
+    ({
+        let res =
+            ((::alloc::fmt::format as
+                    for<'a> fn(Arguments<'a>) -> String {format})(((format_arguments::new_const
+                        as
+                        fn(&[&'static str]) -> Arguments<'_> {Arguments::<'_>::new_const})((&([("test"
+                                    as &str)] as [&str; 1]) as &[&str; 1])) as Arguments<'_>))
+                as String);
+        (res as String)
+    } as String);
+} as ())
 type Foo = [i32; (3 as usize)];
 struct Bar {
     x: [i32; (3 as usize)],
@@ -48,9 +48,9 @@
 enum Baz { BazVariant([i32; (5 as usize)]), }
 fn id<T>(x: T) -> T ({ (x as T) } as T)
 fn use_id() ({
-        let _ =
-            ((id::<[i32; (3 as usize)]> as
-                    fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32),
-                        (2 as i32), (3 as i32)] as [i32; 3])) as [i32; 3]);
-    } as ())
+    let _ =
+        ((id::<[i32; (3 as usize)]> as
+                fn([i32; 3]) -> [i32; 3] {id::<[i32; 3]>})(([(1 as i32),
+                    (2 as i32), (3 as i32)] as [i32; 3])) as [i32; 3]);
+} as ())
 fn main() ({ } as ())
diff --git a/tests/run-make/alloc-no-oom-handling/Makefile b/tests/run-make/alloc-no-oom-handling/Makefile
deleted file mode 100644
index 87f74c6..0000000
--- a/tests/run-make/alloc-no-oom-handling/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-include ../tools.mk
-
-all:
-	$(RUSTC) --edition=2021 -Dwarnings --crate-type=rlib ../../../library/alloc/src/lib.rs --cfg no_global_oom_handling
diff --git a/tests/run-make/alloc-no-oom-handling/rmake.rs b/tests/run-make/alloc-no-oom-handling/rmake.rs
new file mode 100644
index 0000000..fec3c65
--- /dev/null
+++ b/tests/run-make/alloc-no-oom-handling/rmake.rs
@@ -0,0 +1,15 @@
+// This test checks that alloc can still compile correctly
+// when the unstable no_global_oom_handling feature is turned on.
+// See https://github.com/rust-lang/rust/pull/84266
+
+use run_make_support::rustc;
+
+fn main() {
+    rustc()
+        .edition("2021")
+        .arg("-Dwarnings")
+        .crate_type("rlib")
+        .input("../../../library/alloc/src/lib.rs")
+        .cfg("no_global_oom_handling")
+        .run();
+}
diff --git a/tests/run-make/alloc-no-rc/Makefile b/tests/run-make/alloc-no-rc/Makefile
deleted file mode 100644
index 9824b17..0000000
--- a/tests/run-make/alloc-no-rc/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-include ../tools.mk
-
-all:
-	$(RUSTC) --edition=2021 -Dwarnings --crate-type=rlib ../../../library/alloc/src/lib.rs --cfg no_rc
diff --git a/tests/run-make/alloc-no-rc/rmake.rs b/tests/run-make/alloc-no-rc/rmake.rs
new file mode 100644
index 0000000..c5744a3
--- /dev/null
+++ b/tests/run-make/alloc-no-rc/rmake.rs
@@ -0,0 +1,15 @@
+// This test checks that alloc can still compile correctly
+// when the unstable no_rc feature is turned on.
+// See https://github.com/rust-lang/rust/pull/84266
+
+use run_make_support::rustc;
+
+fn main() {
+    rustc()
+        .edition("2021")
+        .arg("-Dwarnings")
+        .crate_type("rlib")
+        .input("../../../library/alloc/src/lib.rs")
+        .cfg("no_rc")
+        .run();
+}
diff --git a/tests/run-make/alloc-no-sync/Makefile b/tests/run-make/alloc-no-sync/Makefile
deleted file mode 100644
index 04ec4c7..0000000
--- a/tests/run-make/alloc-no-sync/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-include ../tools.mk
-
-all:
-	$(RUSTC) --edition=2021 -Dwarnings --crate-type=rlib ../../../library/alloc/src/lib.rs --cfg no_sync
diff --git a/tests/run-make/alloc-no-sync/rmake.rs b/tests/run-make/alloc-no-sync/rmake.rs
new file mode 100644
index 0000000..6410eca
--- /dev/null
+++ b/tests/run-make/alloc-no-sync/rmake.rs
@@ -0,0 +1,15 @@
+// This test checks that alloc can still compile correctly
+// when the unstable no_sync feature is turned on.
+// See https://github.com/rust-lang/rust/pull/84266
+
+use run_make_support::rustc;
+
+fn main() {
+    rustc()
+        .edition("2021")
+        .arg("-Dwarnings")
+        .crate_type("rlib")
+        .input("../../../library/alloc/src/lib.rs")
+        .cfg("no_sync")
+        .run();
+}
diff --git a/tests/run-make/allocator-shim-circular-deps/Makefile b/tests/run-make/allocator-shim-circular-deps/Makefile
index 4624b84..f667e2e 100644
--- a/tests/run-make/allocator-shim-circular-deps/Makefile
+++ b/tests/run-make/allocator-shim-circular-deps/Makefile
@@ -1,3 +1,8 @@
+# This test is designed to intentionally introduce a circular dependency scenario to check that a specific compiler bug doesn't make a resurgence.
+# The bug in question arose when at least one crate required a global allocator, and that crate was placed after the one defining it in the linker order. 
+# The generated symbols.o should not result in any linker errors.
+# See https://github.com/rust-lang/rust/issues/112715
+
 # ignore-cross-compile
 include ../tools.mk
 
diff --git a/tests/run-make/archive-duplicate-names/Makefile b/tests/run-make/archive-duplicate-names/Makefile
index 5433a42..207eee3 100644
--- a/tests/run-make/archive-duplicate-names/Makefile
+++ b/tests/run-make/archive-duplicate-names/Makefile
@@ -1,3 +1,7 @@
+# When two object archives with the same filename are present, an iterator is supposed to inspect each object, recognize the duplication and extract each one to a different directory.
+# This test checks that this duplicate handling behaviour has not been broken.
+# See https://github.com/rust-lang/rust/pull/24439
+
 # ignore-cross-compile
 include ../tools.mk
 
diff --git a/tests/run-make/bare-outfile/Makefile b/tests/run-make/bare-outfile/Makefile
index 23b619e..ad6fe4b 100644
--- a/tests/run-make/bare-outfile/Makefile
+++ b/tests/run-make/bare-outfile/Makefile
@@ -1,3 +1,5 @@
+# This test checks that manually setting the output file as a bare file with no file extension still results in successful compilation.
+
 # ignore-cross-compile
 include ../tools.mk
 
diff --git a/tests/run-make/issue-28766/foo.rs b/tests/run-make/box-struct-no-segfault/foo.rs
similarity index 100%
rename from tests/run-make/issue-28766/foo.rs
rename to tests/run-make/box-struct-no-segfault/foo.rs
diff --git a/tests/run-make/issue-28766/main.rs b/tests/run-make/box-struct-no-segfault/main.rs
similarity index 100%
rename from tests/run-make/issue-28766/main.rs
rename to tests/run-make/box-struct-no-segfault/main.rs
diff --git a/tests/run-make/box-struct-no-segfault/rmake.rs b/tests/run-make/box-struct-no-segfault/rmake.rs
new file mode 100644
index 0000000..5406f76
--- /dev/null
+++ b/tests/run-make/box-struct-no-segfault/rmake.rs
@@ -0,0 +1,13 @@
+// The crate "foo" tied to this test executes a very specific function,
+// which involves boxing an instance of the struct Foo. However,
+// this once caused a segmentation fault in cargo release builds due to an LLVM
+// incorrect assertion.
+// This test checks that this bug does not resurface.
+// See https://github.com/rust-lang/rust/issues/28766
+
+use run_make_support::{rustc, tmp_dir};
+
+fn main() {
+    rustc().opt().input("foo.rs").run();
+    rustc().opt().library_search_path(tmp_dir()).input("main.rs").run();
+}
diff --git a/tests/run-make/c-dynamic-dylib/Makefile b/tests/run-make/c-dynamic-dylib/Makefile
index b5bfbc7..0d40964 100644
--- a/tests/run-make/c-dynamic-dylib/Makefile
+++ b/tests/run-make/c-dynamic-dylib/Makefile
@@ -1,3 +1,6 @@
+# This test checks that dynamic Rust linking with C does not encounter any errors, with dynamic dependencies given preference over static.
+# See https://github.com/rust-lang/rust/issues/10434
+
 # ignore-cross-compile
 include ../tools.mk
 
diff --git a/tests/run-make/c-dynamic-rlib/Makefile b/tests/run-make/c-dynamic-rlib/Makefile
index 0475bd8..a64e89c 100644
--- a/tests/run-make/c-dynamic-rlib/Makefile
+++ b/tests/run-make/c-dynamic-rlib/Makefile
@@ -1,3 +1,6 @@
+# This test checks that dynamic Rust linking with C does not encounter any errors, with static dependencies given preference over dynamic. (This is the default behaviour.)
+# See https://github.com/rust-lang/rust/issues/10434
+
 # ignore-cross-compile
 include ../tools.mk
 
diff --git a/tests/run-make/c-link-to-rust-dylib/Makefile b/tests/run-make/c-link-to-rust-dylib/Makefile
index 2763cb6e..201f717 100644
--- a/tests/run-make/c-link-to-rust-dylib/Makefile
+++ b/tests/run-make/c-link-to-rust-dylib/Makefile
@@ -1,3 +1,6 @@
+# This test checks that C linking with Rust does not encounter any errors, with dynamic libraries.
+# See https://github.com/rust-lang/rust/issues/10434
+
 # ignore-cross-compile
 include ../tools.mk
 
diff --git a/tests/run-make/c-link-to-rust-staticlib/Makefile b/tests/run-make/c-link-to-rust-staticlib/Makefile
deleted file mode 100644
index e14775f..0000000
--- a/tests/run-make/c-link-to-rust-staticlib/Makefile
+++ /dev/null
@@ -1,13 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-# ignore-freebsd
-# FIXME
-
-all:
-	$(RUSTC) foo.rs
-	$(CC) bar.c $(call STATICLIB,foo) $(call OUT_EXE,bar) \
-		$(EXTRACFLAGS) $(EXTRACXXFLAGS)
-	$(call RUN,bar)
-	rm $(call STATICLIB,foo)
-	$(call RUN,bar)
diff --git a/tests/run-make/c-link-to-rust-staticlib/rmake.rs b/tests/run-make/c-link-to-rust-staticlib/rmake.rs
new file mode 100644
index 0000000..63d5eb7
--- /dev/null
+++ b/tests/run-make/c-link-to-rust-staticlib/rmake.rs
@@ -0,0 +1,15 @@
+// This test checks that C linking with Rust does not encounter any errors, with a static library.
+// See https://github.com/rust-lang/rust/issues/10434
+
+//@ ignore-cross-compile
+
+use run_make_support::{cc, extra_c_flags, run, rustc, static_lib};
+use std::fs;
+
+fn main() {
+    rustc().input("foo.rs").run();
+    cc().input("bar.c").input(static_lib("foo")).out_exe("bar").args(&extra_c_flags()).run();
+    run("bar");
+    fs::remove_file(static_lib("foo"));
+    run("bar");
+}
diff --git a/tests/run-make/c-link-to-rust-va-list-fn/Makefile b/tests/run-make/c-link-to-rust-va-list-fn/Makefile
deleted file mode 100644
index 596c0fc..0000000
--- a/tests/run-make/c-link-to-rust-va-list-fn/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-all:
-	$(RUSTC) checkrust.rs
-	$(CC) test.c $(call STATICLIB,checkrust) $(call OUT_EXE,test) $(EXTRACFLAGS)
-	$(call RUN,test)
diff --git a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs
index 5830ef0..e518579 100644
--- a/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs
+++ b/tests/run-make/c-link-to-rust-va-list-fn/checkrust.rs
@@ -1,10 +1,7 @@
 #![crate_type = "staticlib"]
 #![feature(c_variadic)]
-#![feature(rustc_private)]
 
-extern crate libc;
-
-use libc::{c_char, c_double, c_int, c_long, c_longlong};
+use std::ffi::{c_char, c_double, c_int, c_long, c_longlong};
 use std::ffi::VaList;
 use std::ffi::{CString, CStr};
 
diff --git a/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs
new file mode 100644
index 0000000..7a450ef
--- /dev/null
+++ b/tests/run-make/c-link-to-rust-va-list-fn/rmake.rs
@@ -0,0 +1,18 @@
+// test.c and its static library checkrust.rs make use of variadic functions (VaList).
+// This test checks that the use of this feature does not
+// prevent the creation of a functional binary.
+// See https://github.com/rust-lang/rust/pull/49878
+
+//@ ignore-cross-compile
+
+use run_make_support::{cc, extra_c_flags, run, rustc, static_lib};
+
+fn main() {
+    rustc().input("checkrust.rs").run();
+    cc().input("test.c")
+        .input(static_lib("checkrust"))
+        .out_exe("test")
+        .args(&extra_c_flags())
+        .run();
+    run("test");
+}
diff --git a/tests/run-make/c-static-dylib/Makefile b/tests/run-make/c-static-dylib/Makefile
index 4e23edb..05da174 100644
--- a/tests/run-make/c-static-dylib/Makefile
+++ b/tests/run-make/c-static-dylib/Makefile
@@ -1,3 +1,6 @@
+# This test checks that static Rust linking with C does not encounter any errors, with dynamic dependencies given preference over static.
+# See https://github.com/rust-lang/rust/issues/10434
+
 # ignore-cross-compile
 include ../tools.mk
 
diff --git a/tests/run-make/c-static-rlib/Makefile b/tests/run-make/c-static-rlib/Makefile
index 4e35112..298e432 100644
--- a/tests/run-make/c-static-rlib/Makefile
+++ b/tests/run-make/c-static-rlib/Makefile
@@ -1,3 +1,6 @@
+# This test checks that static Rust linking with C does not encounter any errors, with static dependencies given preference over dynamic. (This is the default behaviour.)
+# See https://github.com/rust-lang/rust/issues/10434
+
 # ignore-cross-compile
 include ../tools.mk
 
diff --git a/tests/run-make/c-unwind-abi-catch-lib-panic/Makefile b/tests/run-make/c-unwind-abi-catch-lib-panic/Makefile
index b8e0e94..2bb8d42 100644
--- a/tests/run-make/c-unwind-abi-catch-lib-panic/Makefile
+++ b/tests/run-make/c-unwind-abi-catch-lib-panic/Makefile
@@ -1,3 +1,6 @@
+# Exercise unwinding a panic. This catches a panic across an FFI boundary and downcasts it into an integer. The Rust code that panics is in a separate crate.
+# See https://github.com/rust-lang/rust/commit/baf227ea0c1e07fc54395a51e4b3881d701180cb
+
 # ignore-cross-compile
 # needs-unwind
 include ../tools.mk
diff --git a/tests/run-make/c-unwind-abi-catch-panic/Makefile b/tests/run-make/c-unwind-abi-catch-panic/Makefile
index 1760ddb..0a38d83 100644
--- a/tests/run-make/c-unwind-abi-catch-panic/Makefile
+++ b/tests/run-make/c-unwind-abi-catch-panic/Makefile
@@ -1,3 +1,6 @@
+# Exercise unwinding a panic. This catches a panic across an FFI boundary and downcasts it into an integer. The Rust code that panics is in the same directory.
+# See https://github.com/rust-lang/rust/commit/baf227ea0c1e07fc54395a51e4b3881d701180cb
+
 # ignore-cross-compile
 # needs-unwind
 include ../tools.mk
diff --git a/tests/run-make/cat-and-grep-sanity-check/Makefile b/tests/run-make/cat-and-grep-sanity-check/Makefile
index 82351e2..8ee69c0 100644
--- a/tests/run-make/cat-and-grep-sanity-check/Makefile
+++ b/tests/run-make/cat-and-grep-sanity-check/Makefile
@@ -1,3 +1,7 @@
+# grep in run-make tests was partially replaced with a custom script, CGREP. This tests that CGREP does its job correctly.
+# See https://github.com/rust-lang/rust/commit/ab788a2ee175c7560f0ca58bbc183ecfd57d2f7a
+# FIXME(Oneirical): Note that this test will likely become useless after the port to rmake.rs tests (see https://github.com/rust-lang/rust/issues/121876)
+
 include ../tools.mk
 
 all:
diff --git a/tests/run-make/cdylib-dylib-linkage/Makefile b/tests/run-make/cdylib-dylib-linkage/Makefile
index 51fbfef..db8393d 100644
--- a/tests/run-make/cdylib-dylib-linkage/Makefile
+++ b/tests/run-make/cdylib-dylib-linkage/Makefile
@@ -1,3 +1,6 @@
+# This test checks that cdylibs can link against dylibs as dependencies, after this restriction was disabled.
+# See https://github.com/rust-lang/rust/commit/72aaa3a414d17aa0c4f19feafa5bab5f84b60e63
+
 # ignore-cross-compile
 include ../tools.mk
 
diff --git a/tests/run-make/cdylib-fewer-symbols/Makefile b/tests/run-make/cdylib-fewer-symbols/Makefile
index 4e08f97..d587cec 100644
--- a/tests/run-make/cdylib-fewer-symbols/Makefile
+++ b/tests/run-make/cdylib-fewer-symbols/Makefile
@@ -1,6 +1,8 @@
 # ignore-cross-compile
+
 # Test that allocator-related symbols don't show up as exported from a cdylib as
 # they're internal to Rust and not part of the public ABI.
+# See https://github.com/rust-lang/rust/commit/fbf98697021173a30b84d9145df0966a23a2f9d2
 
 include ../tools.mk
 
diff --git a/tests/run-make/cdylib/Makefile b/tests/run-make/cdylib/Makefile
index 3c8b526..2c6414c 100644
--- a/tests/run-make/cdylib/Makefile
+++ b/tests/run-make/cdylib/Makefile
@@ -1,3 +1,6 @@
+# When the cdylib crate type was added as a variation of dylib, it needed a test to check its function.
+# See https://github.com/rust-lang/rust/pull/33553
+
 # ignore-cross-compile
 include ../tools.mk
 
diff --git a/tests/run-make/codegen-options-parsing/Makefile b/tests/run-make/codegen-options-parsing/Makefile
index 56bb900..beaf233 100644
--- a/tests/run-make/codegen-options-parsing/Makefile
+++ b/tests/run-make/codegen-options-parsing/Makefile
@@ -1,3 +1,5 @@
+# This test intentionally feeds invalid inputs to codegen and checks if the error message outputs contain specific helpful indications.
+
 # ignore-cross-compile
 include ../tools.mk
 
diff --git a/tests/run-make/comment-section/Makefile b/tests/run-make/comment-section/Makefile
index 9f81006..d0b9817 100644
--- a/tests/run-make/comment-section/Makefile
+++ b/tests/run-make/comment-section/Makefile
@@ -1,3 +1,6 @@
+# Both GCC and Clang write by default a `.comment` section with compiler information. Rustc received a similar .comment section, so this tests checks that this section properly appears.
+# See https://github.com/rust-lang/rust/commit/74b8d324eb77a8f337b35dc68ac91b0c2c06debc
+
 include ../tools.mk
 
 # only-linux
diff --git a/tests/run-make/compile-stdin/Makefile b/tests/run-make/compile-stdin/Makefile
index 2a49528..b3d7cc7 100644
--- a/tests/run-make/compile-stdin/Makefile
+++ b/tests/run-make/compile-stdin/Makefile
@@ -1,3 +1,6 @@
+# When provided standard input piped directly into rustc, this test checks that the compilation completes successfully and that the output can be executed.
+# See https://github.com/rust-lang/rust/pull/28805
+
 # ignore-cross-compile
 include ../tools.mk
 
diff --git a/tests/run-make/compiler-lookup-paths-2/Makefile b/tests/run-make/compiler-lookup-paths-2/Makefile
index d4ff7d8..ecc0577 100644
--- a/tests/run-make/compiler-lookup-paths-2/Makefile
+++ b/tests/run-make/compiler-lookup-paths-2/Makefile
@@ -1,3 +1,6 @@
+# This test checks that extern crate declarations in Cargo without a corresponding declaration in the manifest of a dependency are NOT allowed.
+# See https://github.com/rust-lang/rust/pull/21113
+
 include ../tools.mk
 
 all:
diff --git a/tests/run-make/compiler-lookup-paths/Makefile b/tests/run-make/compiler-lookup-paths/Makefile
index 310d677..fc0cbde 100644
--- a/tests/run-make/compiler-lookup-paths/Makefile
+++ b/tests/run-make/compiler-lookup-paths/Makefile
@@ -1,3 +1,6 @@
+# rustc supports different types of lookup paths, such as dependency, native or crate. This test checks that these lookup paths are functional and result in functional compilation.
+# See https://github.com/rust-lang/rust/pull/19941
+
 include ../tools.mk
 
 # ignore-wasm32 (need a C compiler)
diff --git a/tests/run-make/const_fn_mir/dump.mir b/tests/run-make/const_fn_mir/dump.mir
index ced170b..b1802c9 100644
--- a/tests/run-make/const_fn_mir/dump.mir
+++ b/tests/run-make/const_fn_mir/dump.mir
@@ -5,7 +5,7 @@
     let mut _1: (i32, bool);
 
     bb0: {
-        _1 = CheckedAdd(const 5_i32, const 6_i32);
+        _1 = AddWithOverflow(const 5_i32, const 6_i32);
         assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 5_i32, const 6_i32) -> [success: bb1, unwind continue];
     }
 
@@ -21,7 +21,7 @@
     let mut _1: (i32, bool);
 
     bb0: {
-        _1 = CheckedAdd(const 5_i32, const 6_i32);
+        _1 = AddWithOverflow(const 5_i32, const 6_i32);
         assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 5_i32, const 6_i32) -> [success: bb1, unwind continue];
     }
 
diff --git a/tests/run-make/core-no-fp-fmt-parse/rmake.rs b/tests/run-make/core-no-fp-fmt-parse/rmake.rs
index e348488..aef28fd 100644
--- a/tests/run-make/core-no-fp-fmt-parse/rmake.rs
+++ b/tests/run-make/core-no-fp-fmt-parse/rmake.rs
@@ -2,7 +2,6 @@
 // support for formatting and parsing floating-point numbers.
 
 use run_make_support::rustc;
-use std::path::PathBuf;
 
 fn main() {
     rustc()
diff --git a/tests/run-make/doctests-keep-binaries/rmake.rs b/tests/run-make/doctests-keep-binaries/rmake.rs
index ad0c276..0613ef4 100644
--- a/tests/run-make/doctests-keep-binaries/rmake.rs
+++ b/tests/run-make/doctests-keep-binaries/rmake.rs
@@ -26,8 +26,7 @@
             .arg("--test")
             .arg("--persist-doctests")
             .arg(out_dir)
-            .arg("--extern")
-            .arg(format!("t={}", extern_path.display()))
+            .extern_("t", extern_path)
             .run();
         check_generated_binaries();
     });
@@ -38,8 +37,7 @@
             .arg("--test")
             .arg("--persist-doctests")
             .arg(out_dir)
-            .arg("--extern")
-            .arg(format!("t={}", extern_path.display()))
+            .extern_("t", extern_path)
             .arg("--no-run")
             .run();
         check_generated_binaries();
@@ -59,8 +57,7 @@
             .arg("doctests")
             .arg("--test-run-directory")
             .arg(run_dir)
-            .arg("--extern")
-            .arg("t=libt.rlib")
+            .extern_("t", "libt.rlib")
             .run();
 
         remove_dir_all(run_dir_path);
diff --git a/tests/run-make/doctests-runtool/rmake.rs b/tests/run-make/doctests-runtool/rmake.rs
index 6f89bf2..6cc7c6b 100644
--- a/tests/run-make/doctests-runtool/rmake.rs
+++ b/tests/run-make/doctests-runtool/rmake.rs
@@ -29,8 +29,7 @@
         .arg(run_dir_name)
         .arg("--runtool")
         .arg(&run_tool_binary)
-        .arg("--extern")
-        .arg("t=libt.rlib")
+        .extern_("t", "libt.rlib")
         .current_dir(tmp_dir())
         .run();
 
diff --git a/tests/run-make/issue-11908/Makefile b/tests/run-make/issue-11908/Makefile
deleted file mode 100644
index 3858666..0000000
--- a/tests/run-make/issue-11908/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-# ignore-cross-compile
-# This test ensures that if you have the same rlib or dylib at two locations
-# in the same path that you don't hit an assertion in the compiler.
-#
-# Note that this relies on `liburl` to be in the path somewhere else,
-# and then our aux-built libraries will collide with liburl (they have
-# the same version listed)
-
-include ../tools.mk
-
-all:
-	mkdir $(TMPDIR)/other
-	$(RUSTC) foo.rs --crate-type=dylib -C prefer-dynamic
-	mv $(call DYLIB,foo) $(TMPDIR)/other
-	$(RUSTC) foo.rs --crate-type=dylib -C prefer-dynamic
-	$(RUSTC) bar.rs -L $(TMPDIR)/other
-	rm -rf $(TMPDIR)
-	mkdir -p $(TMPDIR)/other
-	$(RUSTC) foo.rs --crate-type=rlib
-	mv $(TMPDIR)/libfoo.rlib $(TMPDIR)/other
-	$(RUSTC) foo.rs --crate-type=rlib
-	$(RUSTC) bar.rs -L $(TMPDIR)/other
diff --git a/tests/run-make/issue-14500/Makefile b/tests/run-make/issue-14500/Makefile
deleted file mode 100644
index eeab48d..0000000
--- a/tests/run-make/issue-14500/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-include ../tools.mk
-
-# ignore-cross-compile
-
-# Test to make sure that reachable extern fns are always available in final
-# productcs, including when LTO is used. In this test, the `foo` crate has a
-# reahable symbol, and is a dependency of the `bar` crate. When the `bar` crate
-# is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the
-# only way that `foo.c` will successfully compile.
-
-all:
-	$(RUSTC) foo.rs --crate-type=rlib
-	$(RUSTC) bar.rs --crate-type=staticlib -C lto -L. -o $(TMPDIR)/libbar.a
-	$(CC) foo.c $(TMPDIR)/libbar.a $(EXTRACFLAGS) $(call OUT_EXE,foo)
-	$(call RUN,foo)
diff --git a/tests/run-make/issue-28766/Makefile b/tests/run-make/issue-28766/Makefile
deleted file mode 100644
index 96d0bdc..0000000
--- a/tests/run-make/issue-28766/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-include ../tools.mk
-
-all:
-	$(RUSTC) -O foo.rs
-	$(RUSTC) -O -L $(TMPDIR) main.rs
diff --git a/tests/run-make/issue64319/Makefile b/tests/run-make/issue64319/Makefile
deleted file mode 100644
index 56346cb..0000000
--- a/tests/run-make/issue64319/Makefile
+++ /dev/null
@@ -1,40 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-# Different optimization levels imply different values for `-Zshare-generics`,
-# so try out a whole bunch of combinations to make sure everything is compatible
-all:
-	# First up, try some defaults
-	$(RUSTC) --crate-type rlib foo.rs
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=3
-
-	# Next try mixing up some things explicitly
-	$(RUSTC) --crate-type rlib foo.rs -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=no
-	$(RUSTC) --crate-type rlib foo.rs -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes
-	$(RUSTC) --crate-type rlib foo.rs -Z share-generics=yes
-	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=no
-	$(RUSTC) --crate-type rlib foo.rs -Z share-generics=yes
-	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes
-
-	# Now combine a whole bunch of options together
-	$(RUSTC) --crate-type rlib foo.rs
-	$(RUSTC) --crate-type dylib bar.rs
-	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -Z share-generics=yes
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=1
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=1 -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=1 -Z share-generics=yes
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=2
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=2 -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=2 -Z share-generics=yes
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=3
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=3 -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=3 -Z share-generics=yes
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=s
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=s -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=s -Z share-generics=yes
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=z
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=z -Z share-generics=no
-	$(RUSTC) --crate-type dylib bar.rs -C opt-level=z -Z share-generics=yes
diff --git a/tests/run-make/libtest-padding/Makefile b/tests/run-make/libtest-padding/Makefile
index 42bc119..c8e2fc0 100644
--- a/tests/run-make/libtest-padding/Makefile
+++ b/tests/run-make/libtest-padding/Makefile
@@ -2,7 +2,7 @@
 # needs-unwind because #[bench] and -Cpanic=abort requires -Zpanic-abort-tests
 include ../tools.mk
 
-NORMALIZE=sed 's%[0-9,]\{1,\} ns/iter (+/- [0-9,]\{1,\})%?? ns/iter (+/- ??)%' | sed 's%finished in [0-9\.]\{1,\}%finished in ??%'
+NORMALIZE=sed 's%[0-9,\.]\{1,\} ns/iter (+/- [0-9,\.]\{1,\})%?? ns/iter (+/- ??)%' | sed 's%finished in [0-9\.]\{1,\}%finished in ??%'
 
 all:
 	$(RUSTC) --test tests.rs
diff --git a/tests/run-make/link-path-order/main.rs b/tests/run-make/link-path-order/main.rs
index 8024e34..20a517d 100644
--- a/tests/run-make/link-path-order/main.rs
+++ b/tests/run-make/link-path-order/main.rs
@@ -1,10 +1,8 @@
-#![feature(rustc_private)]
-
-extern crate libc;
+use std::ffi::c_int;
 
 #[link(name = "foo", kind = "static")]
 extern "C" {
-    fn should_return_one() -> libc::c_int;
+    fn should_return_one() -> c_int;
 }
 
 fn main() {
diff --git a/tests/run-make/no-cdylib-as-rdylib/Makefile b/tests/run-make/no-cdylib-as-rdylib/Makefile
deleted file mode 100644
index 4d2be0a..0000000
--- a/tests/run-make/no-cdylib-as-rdylib/Makefile
+++ /dev/null
@@ -1,16 +0,0 @@
-# ignore-cross-compile
-include ../tools.mk
-
-# Test that rustc will not attempt to link against a cdylib as if
-# it is a rust dylib when an rlib for the same crate is available.
-# Previously rustc didn't actually check if any further formats of
-# a crate which has been loaded are of the same version and if
-# they are actually valid. This caused a cdylib to be interpreted
-# as rust dylib as soon as the corresponding rlib was loaded. As
-# cdylibs don't export any rust symbols, linking would fail if
-# rustc decides to link against the cdylib rather than the rlib.
-
-all:
-	$(RUSTC) bar.rs --crate-type=rlib --crate-type=cdylib
-	$(RUSTC) foo.rs -C prefer-dynamic
-	$(call RUN,foo)
diff --git a/tests/run-make/no-cdylib-as-rdylib/rmake.rs b/tests/run-make/no-cdylib-as-rdylib/rmake.rs
new file mode 100644
index 0000000..42e89df
--- /dev/null
+++ b/tests/run-make/no-cdylib-as-rdylib/rmake.rs
@@ -0,0 +1,16 @@
+// This test produces an rlib and a cdylib from bar.rs.
+// Then, foo.rs attempts to link to the bar library.
+// If the test passes, that means rustc favored the rlib and ignored the cdylib.
+// If the test fails, that is because the cdylib was picked, which does not export
+// any Rust symbols.
+// See https://github.com/rust-lang/rust/pull/113695
+
+//@ ignore-cross-compile
+
+use run_make_support::{run, rustc};
+
+fn main() {
+    rustc().input("bar.rs").crate_type("rlib").crate_type("cdylib").run();
+    rustc().input("foo.rs").arg("-Cprefer-dynamic").run();
+    run("foo");
+}
diff --git a/tests/run-make/no-intermediate-extras/Makefile b/tests/run-make/no-intermediate-extras/Makefile
deleted file mode 100644
index 83b5ced..0000000
--- a/tests/run-make/no-intermediate-extras/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# ignore-cross-compile
-# Regression test for issue #10973
-
-include ../tools.mk
-
-all:
-	$(RUSTC) --crate-type=rlib --test foo.rs
-	rm $(TMPDIR)/foo.bc && exit 1 || exit 0
diff --git a/tests/run-make/no-intermediate-extras/rmake.rs b/tests/run-make/no-intermediate-extras/rmake.rs
new file mode 100644
index 0000000..19479e3
--- /dev/null
+++ b/tests/run-make/no-intermediate-extras/rmake.rs
@@ -0,0 +1,17 @@
+// When using the --test flag with an rlib, this used to generate
+// an unwanted .bc file, which should not exist. This test checks
+// that the bug causing the generation of this file has not returned.
+// See https://github.com/rust-lang/rust/issues/10973
+
+//@ ignore-cross-compile
+
+use run_make_support::{rustc, tmp_dir};
+use std::fs;
+
+fn main() {
+    rustc().crate_type("rlib").arg("--test").input("foo.rs").run();
+    assert!(
+        fs::remove_file(tmp_dir().join("foo.bc")).is_err(),
+        "An unwanted .bc file was created by run-make/no-intermediate-extras."
+    );
+}
diff --git a/tests/run-make/panic-impl-transitive/Makefile b/tests/run-make/panic-impl-transitive/Makefile
deleted file mode 100644
index 9a271a2..0000000
--- a/tests/run-make/panic-impl-transitive/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-include ../tools.mk
-
-# NOTE we use --emit=llvm-ir to avoid running the linker (linking will fail because there's no main
-# in this crate)
-all:
-	$(RUSTC) panic-impl-provider.rs
-	$(RUSTC) panic-impl-consumer.rs -C panic=abort --emit=llvm-ir -L $(TMPDIR)
diff --git a/tests/run-make/panic-impl-transitive/rmake.rs b/tests/run-make/panic-impl-transitive/rmake.rs
new file mode 100644
index 0000000..86308f5
--- /dev/null
+++ b/tests/run-make/panic-impl-transitive/rmake.rs
@@ -0,0 +1,19 @@
+// In Rust programs where the standard library is unavailable (#![no_std]), we may be interested
+// in customizing how panics are handled. Here, the provider specifies that panics should be handled
+// by entering an infinite loop. This test checks that this panic implementation can be transitively
+// provided by an external crate.
+// --emit=llvm-ir is used to avoid running the linker, as linking will fail due to the lack of main
+// function in the crate.
+// See https://github.com/rust-lang/rust/pull/50338
+
+use run_make_support::{rustc, tmp_dir};
+
+fn main() {
+    rustc().input("panic-impl-provider.rs").run();
+    rustc()
+        .input("panic-impl-consumer.rs")
+        .panic("abort")
+        .emit("llvm-ir")
+        .library_search_path(tmp_dir())
+        .run();
+}
diff --git a/tests/run-make/issue-14500/bar.rs b/tests/run-make/reachable-extern-fn-available-lto/bar.rs
similarity index 100%
rename from tests/run-make/issue-14500/bar.rs
rename to tests/run-make/reachable-extern-fn-available-lto/bar.rs
diff --git a/tests/run-make/issue-14500/foo.c b/tests/run-make/reachable-extern-fn-available-lto/foo.c
similarity index 100%
rename from tests/run-make/issue-14500/foo.c
rename to tests/run-make/reachable-extern-fn-available-lto/foo.c
diff --git a/tests/run-make/issue-14500/foo.rs b/tests/run-make/reachable-extern-fn-available-lto/foo.rs
similarity index 100%
rename from tests/run-make/issue-14500/foo.rs
rename to tests/run-make/reachable-extern-fn-available-lto/foo.rs
diff --git a/tests/run-make/reachable-extern-fn-available-lto/rmake.rs b/tests/run-make/reachable-extern-fn-available-lto/rmake.rs
new file mode 100644
index 0000000..c7262b9
--- /dev/null
+++ b/tests/run-make/reachable-extern-fn-available-lto/rmake.rs
@@ -0,0 +1,26 @@
+// Test to make sure that reachable extern fns are always available in final
+// productcs, including when link time optimizations (LTO) are used.
+
+// In this test, the `foo` crate has a reahable symbol,
+// and is a dependency of the `bar` crate. When the `bar` crate
+// is compiled with LTO, it shouldn't strip the symbol from `foo`, and that's the
+// only way that `foo.c` will successfully compile.
+// See https://github.com/rust-lang/rust/issues/14500
+
+//@ ignore-cross-compile
+
+use run_make_support::{cc, extra_c_flags, run, rustc, static_lib};
+
+fn main() {
+    let libbar_path = static_lib("bar");
+    rustc().input("foo.rs").crate_type("rlib").run();
+    rustc()
+        .input("bar.rs")
+        .crate_type("staticlib")
+        .arg("-Clto")
+        .library_search_path(".")
+        .output(&libbar_path)
+        .run();
+    cc().input("foo.c").input(libbar_path).args(&extra_c_flags()).out_exe("foo").run();
+    run("foo");
+}
diff --git a/tests/run-make/rust-lld-by-default/main.rs b/tests/run-make/rust-lld-by-default/main.rs
new file mode 100644
index 0000000..e9f655f
--- /dev/null
+++ b/tests/run-make/rust-lld-by-default/main.rs
@@ -0,0 +1,5 @@
+// Test linking using `cc` with `rust-lld`, which is on by default on the x86_64-unknown-linux-gnu
+// target.
+// See https://github.com/rust-lang/compiler-team/issues/510 for more info
+
+fn main() {}
diff --git a/tests/run-make/rust-lld-by-default/rmake.rs b/tests/run-make/rust-lld-by-default/rmake.rs
new file mode 100644
index 0000000..8769687
--- /dev/null
+++ b/tests/run-make/rust-lld-by-default/rmake.rs
@@ -0,0 +1,43 @@
+// Ensure that rust-lld is used as the default linker on `x86_64-unknown-linux-gnu`, and that it can
+// also be turned off with a CLI flag.
+
+//@ needs-rust-lld
+//@ only-x86_64-unknown-linux-gnu
+
+extern crate run_make_support;
+
+use run_make_support::regex::Regex;
+use run_make_support::rustc;
+use std::process::Output;
+
+fn main() {
+    // A regular compilation should use rust-lld by default. We'll check that by asking the linker
+    // to display its version number with a link-arg.
+    let output = rustc()
+        .env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info")
+        .link_arg("-Wl,-v")
+        .input("main.rs")
+        .run();
+    assert!(
+        find_lld_version_in_logs(output),
+        "the LLD version string should be present in the output logs"
+    );
+
+    // But it can still be disabled by turning the linker feature off.
+    let output = rustc()
+        .env("RUSTC_LOG", "rustc_codegen_ssa::back::link=info")
+        .link_arg("-Wl,-v")
+        .arg("-Zlinker-features=-lld")
+        .input("main.rs")
+        .run();
+    assert!(
+        !find_lld_version_in_logs(output),
+        "the LLD version string should not be present in the output logs"
+    );
+}
+
+fn find_lld_version_in_logs(output: Output) -> bool {
+    let lld_version_re = Regex::new(r"^LLD [0-9]+\.[0-9]+\.[0-9]+").unwrap();
+    let stderr = std::str::from_utf8(&output.stderr).unwrap();
+    stderr.lines().any(|line| lld_version_re.is_match(line))
+}
diff --git a/tests/run-make/rustdoc-map-file/Makefile b/tests/run-make/rustdoc-map-file/Makefile
deleted file mode 100644
index 5cbf774..0000000
--- a/tests/run-make/rustdoc-map-file/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-include ../tools.mk
-
-all:
-	$(RUSTDOC) -Z unstable-options --generate-redirect-map foo.rs -o "$(TMPDIR)/out"
-	"$(PYTHON)" validate_json.py "$(TMPDIR)/out"
diff --git a/tests/run-make/rustdoc-map-file/rmake.rs b/tests/run-make/rustdoc-map-file/rmake.rs
new file mode 100644
index 0000000..d017b41
--- /dev/null
+++ b/tests/run-make/rustdoc-map-file/rmake.rs
@@ -0,0 +1,13 @@
+use run_make_support::{python_command, rustdoc, tmp_dir};
+
+fn main() {
+    let out_dir = tmp_dir().join("out");
+    rustdoc()
+        .input("foo.rs")
+        .arg("-Zunstable-options")
+        .arg("--generate-redirect-map")
+        .output(&out_dir)
+        .run();
+    // FIXME (GuillaumeGomez): Port the python script to Rust as well.
+    assert!(python_command().arg("validate_json.py").arg(&out_dir).status().unwrap().success());
+}
diff --git a/tests/run-make/rustdoc-output-path/Makefile b/tests/run-make/rustdoc-output-path/Makefile
deleted file mode 100644
index 8f5cda9..0000000
--- a/tests/run-make/rustdoc-output-path/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-include ../tools.mk
-
-all:
-	$(RUSTDOC) -o "$(TMPDIR)/foo/bar/doc" foo.rs
diff --git a/tests/run-make/rustdoc-output-path/rmake.rs b/tests/run-make/rustdoc-output-path/rmake.rs
new file mode 100644
index 0000000..74fb0a5
--- /dev/null
+++ b/tests/run-make/rustdoc-output-path/rmake.rs
@@ -0,0 +1,9 @@
+// Checks that if the output folder doesn't exist, rustdoc will create it.
+
+use run_make_support::{rustdoc, tmp_dir};
+
+fn main() {
+    let out_dir = tmp_dir().join("foo/bar/doc");
+    rustdoc().input("foo.rs").output(&out_dir).run();
+    assert!(out_dir.exists());
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-invalid-expr/Makefile b/tests/run-make/rustdoc-scrape-examples-invalid-expr/Makefile
deleted file mode 100644
index 7786ff7..0000000
--- a/tests/run-make/rustdoc-scrape-examples-invalid-expr/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-deps := ex
-
-include ../rustdoc-scrape-examples-multiple/scrape.mk
-
-all: scrape
diff --git a/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs b/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs
new file mode 100644
index 0000000..e9c54fa
--- /dev/null
+++ b/tests/run-make/rustdoc-scrape-examples-invalid-expr/rmake.rs
@@ -0,0 +1,6 @@
+#[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
+mod scrape;
+
+fn main() {
+    scrape::scrape(&[]);
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-multiple/Makefile b/tests/run-make/rustdoc-scrape-examples-multiple/Makefile
deleted file mode 100644
index 453a7d4..0000000
--- a/tests/run-make/rustdoc-scrape-examples-multiple/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-deps := ex ex2
-
-include ./scrape.mk
-
-all: scrape
diff --git a/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs b/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs
new file mode 100644
index 0000000..e9c54fa
--- /dev/null
+++ b/tests/run-make/rustdoc-scrape-examples-multiple/rmake.rs
@@ -0,0 +1,6 @@
+#[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
+mod scrape;
+
+fn main() {
+    scrape::scrape(&[]);
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-multiple/scrape.mk b/tests/run-make/rustdoc-scrape-examples-multiple/scrape.mk
deleted file mode 100644
index 57220bc..0000000
--- a/tests/run-make/rustdoc-scrape-examples-multiple/scrape.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-include ../tools.mk
-
-OUTPUT_DIR := "$(TMPDIR)/rustdoc"
-
-$(TMPDIR)/%.calls: $(TMPDIR)/libfoobar.rmeta
-	$(RUSTDOC) examples/$*.rs --crate-name $* --crate-type bin --output $(OUTPUT_DIR) \
-	  --extern foobar=$(TMPDIR)/libfoobar.rmeta \
-		-Z unstable-options \
-		--scrape-examples-output-path $@ \
-		--scrape-examples-target-crate foobar \
-		$(extra_flags)
-
-$(TMPDIR)/lib%.rmeta: src/lib.rs
-	$(RUSTC) src/lib.rs --crate-name $* --crate-type lib --emit=metadata
-
-scrape: $(foreach d,$(deps),$(TMPDIR)/$(d).calls)
-	$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --output $(OUTPUT_DIR) \
-		-Z unstable-options \
-		$(foreach d,$(deps),--with-examples $(TMPDIR)/$(d).calls)
-
-	$(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
diff --git a/tests/run-make/rustdoc-scrape-examples-ordering/Makefile b/tests/run-make/rustdoc-scrape-examples-ordering/Makefile
deleted file mode 100644
index bf45b81..0000000
--- a/tests/run-make/rustdoc-scrape-examples-ordering/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-deps := ex1 ex2
-
-include ../rustdoc-scrape-examples-multiple/scrape.mk
-
-all: scrape
diff --git a/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs b/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs
new file mode 100644
index 0000000..e9c54fa
--- /dev/null
+++ b/tests/run-make/rustdoc-scrape-examples-ordering/rmake.rs
@@ -0,0 +1,6 @@
+#[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
+mod scrape;
+
+fn main() {
+    scrape::scrape(&[]);
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-remap/Makefile b/tests/run-make/rustdoc-scrape-examples-remap/Makefile
deleted file mode 100644
index 7786ff7..0000000
--- a/tests/run-make/rustdoc-scrape-examples-remap/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-deps := ex
-
-include ../rustdoc-scrape-examples-multiple/scrape.mk
-
-all: scrape
diff --git a/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs b/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs
new file mode 100644
index 0000000..4e3b895
--- /dev/null
+++ b/tests/run-make/rustdoc-scrape-examples-remap/rmake.rs
@@ -0,0 +1,5 @@
+mod scrape;
+
+fn main() {
+    scrape::scrape(&[]);
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs
new file mode 100644
index 0000000..563e3ac
--- /dev/null
+++ b/tests/run-make/rustdoc-scrape-examples-remap/scrape.rs
@@ -0,0 +1,50 @@
+use run_make_support::{htmldocck, rustc, rustdoc, source_path, tmp_dir};
+use std::fs::read_dir;
+use std::path::Path;
+
+pub fn scrape(extra_args: &[&str]) {
+    let lib_dir = tmp_dir();
+    let out_dir = tmp_dir().join("rustdoc");
+    let crate_name = "foobar";
+    let deps = read_dir("examples")
+        .unwrap()
+        .filter_map(|entry| entry.ok().map(|e| e.path()))
+        .filter(|path| path.is_file() && path.extension().is_some_and(|ext| ext == "rs"))
+        .collect::<Vec<_>>();
+
+    rustc().input("src/lib.rs").crate_name(crate_name).crate_type("lib").emit("metadata").run();
+
+    let mut out_deps = Vec::with_capacity(deps.len());
+    for dep in deps {
+        let dep_stem = dep.file_stem().unwrap();
+        let out_example = out_dir.join(format!("{}.calls", dep_stem.to_str().unwrap()));
+        rustdoc()
+            .input(&dep)
+            .crate_name(&dep_stem)
+            .crate_type("bin")
+            .output(&out_dir)
+            .extern_(crate_name, lib_dir.join(format!("lib{crate_name}.rmeta")))
+            .arg("-Zunstable-options")
+            .arg("--scrape-examples-output-path")
+            .arg(&out_example)
+            .arg("--scrape-examples-target-crate")
+            .arg(crate_name)
+            .args(extra_args)
+            .run();
+        out_deps.push(out_example);
+    }
+
+    let mut rustdoc = rustdoc();
+    rustdoc
+        .input("src/lib.rs")
+        .output(&out_dir)
+        .crate_name(crate_name)
+        .crate_type("lib")
+        .arg("-Zunstable-options");
+    for dep in out_deps {
+        rustdoc.arg("--with-examples").arg(dep);
+    }
+    rustdoc.run();
+
+    assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-test/Makefile b/tests/run-make/rustdoc-scrape-examples-test/Makefile
deleted file mode 100644
index 1235ead..0000000
--- a/tests/run-make/rustdoc-scrape-examples-test/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-extra_flags := --scrape-tests
-deps := ex
-
-include ../rustdoc-scrape-examples-multiple/scrape.mk
-
-all: scrape
diff --git a/tests/run-make/rustdoc-scrape-examples-test/rmake.rs b/tests/run-make/rustdoc-scrape-examples-test/rmake.rs
new file mode 100644
index 0000000..f96ba11
--- /dev/null
+++ b/tests/run-make/rustdoc-scrape-examples-test/rmake.rs
@@ -0,0 +1,6 @@
+#[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
+mod scrape;
+
+fn main() {
+    scrape::scrape(&["--scrape-tests"]);
+}
diff --git a/tests/run-make/rustdoc-scrape-examples-whitespace/Makefile b/tests/run-make/rustdoc-scrape-examples-whitespace/Makefile
deleted file mode 100644
index 7786ff7..0000000
--- a/tests/run-make/rustdoc-scrape-examples-whitespace/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-deps := ex
-
-include ../rustdoc-scrape-examples-multiple/scrape.mk
-
-all: scrape
diff --git a/tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs b/tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs
new file mode 100644
index 0000000..e9c54fa
--- /dev/null
+++ b/tests/run-make/rustdoc-scrape-examples-whitespace/rmake.rs
@@ -0,0 +1,6 @@
+#[path = "../rustdoc-scrape-examples-remap/scrape.rs"]
+mod scrape;
+
+fn main() {
+    scrape::scrape(&[]);
+}
diff --git a/tests/run-make/rustdoc-shared-flags/Makefile b/tests/run-make/rustdoc-shared-flags/Makefile
deleted file mode 100644
index a2a7d7b..0000000
--- a/tests/run-make/rustdoc-shared-flags/Makefile
+++ /dev/null
@@ -1,18 +0,0 @@
-include ../tools.mk
-
-all: z_help c_help list_passes
-
-c_help:
-	$(RUSTC) -C help > $(TMPDIR)/rustc.c_help.txt
-	$(RUSTDOC) -C help > $(TMPDIR)/rustdoc.c_help.txt
-	$(DIFF) $(TMPDIR)/rustc.c_help.txt $(TMPDIR)/rustdoc.c_help.txt
-
-z_help:
-	$(RUSTC) -Z help > $(TMPDIR)/rustc.z_help.txt
-	$(RUSTDOC) -Z help > $(TMPDIR)/rustdoc.z_help.txt
-	$(DIFF) $(TMPDIR)/rustc.z_help.txt $(TMPDIR)/rustdoc.z_help.txt
-
-list_passes:
-	$(RUSTC) -C passes=list > $(TMPDIR)/rustc.passes.txt
-	$(RUSTDOC) -C passes=list > $(TMPDIR)/rustdoc.passes.txt
-	$(DIFF) $(TMPDIR)/rustc.passes.txt $(TMPDIR)/rustdoc.passes.txt
diff --git a/tests/run-make/rustdoc-shared-flags/rmake.rs b/tests/run-make/rustdoc-shared-flags/rmake.rs
new file mode 100644
index 0000000..2db613f
--- /dev/null
+++ b/tests/run-make/rustdoc-shared-flags/rmake.rs
@@ -0,0 +1,14 @@
+use run_make_support::{rustc, rustdoc, Diff};
+
+fn compare_outputs(args: &[&str]) {
+    let rustc_output = String::from_utf8(rustc().args(args).command_output().stdout).unwrap();
+    let rustdoc_output = String::from_utf8(rustdoc().args(args).command_output().stdout).unwrap();
+
+    Diff::new().expected_text("rustc", rustc_output).actual_text("rustdoc", rustdoc_output).run();
+}
+
+fn main() {
+    compare_outputs(&["-C", "help"]);
+    compare_outputs(&["-Z", "help"]);
+    compare_outputs(&["-C", "passes=list"]);
+}
diff --git a/tests/run-make/rustdoc-target-spec-json-path/Makefile b/tests/run-make/rustdoc-target-spec-json-path/Makefile
deleted file mode 100644
index 6d0bc41..0000000
--- a/tests/run-make/rustdoc-target-spec-json-path/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-include ../tools.mk
-
-# Test that rustdoc will properly canonicalize the target spec json path just like rustc
-
-OUTPUT_DIR := "$(TMPDIR)/rustdoc-target-spec-json-path"
-
-all:
-	$(RUSTC) --crate-type lib dummy_core.rs --target target.json
-	$(RUSTDOC) -o $(OUTPUT_DIR) -L $(TMPDIR) my_crate.rs --target target.json
diff --git a/tests/run-make/rustdoc-target-spec-json-path/rmake.rs b/tests/run-make/rustdoc-target-spec-json-path/rmake.rs
new file mode 100644
index 0000000..66530a4
--- /dev/null
+++ b/tests/run-make/rustdoc-target-spec-json-path/rmake.rs
@@ -0,0 +1,14 @@
+// Test that rustdoc will properly canonicalize the target spec json path just like rustc.
+
+use run_make_support::{rustc, rustdoc, tmp_dir};
+
+fn main() {
+    let out_dir = tmp_dir().join("rustdoc-target-spec-json-path");
+    rustc().crate_type("lib").input("dummy_core.rs").target("target.json").run();
+    rustdoc()
+        .input("my_crate.rs")
+        .output(out_dir)
+        .library_search_path(tmp_dir())
+        .target("target.json")
+        .run();
+}
diff --git a/tests/run-make/rustdoc-themes/Makefile b/tests/run-make/rustdoc-themes/Makefile
deleted file mode 100644
index a4980eb..0000000
--- a/tests/run-make/rustdoc-themes/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-include ../tools.mk
-
-# Test that rustdoc will properly load in a theme file and display it in the theme selector.
-
-OUTPUT_DIR := "$(TMPDIR)/rustdoc-themes"
-
-all:
-	awk '/Begin theme: light/ {in_theme=1;next} /End theme:/ {in_theme=0} { if (in_theme) print }' \
-		< '$(S)/src/librustdoc/html/static/css/noscript.css' > '$(TMPDIR)/test.css'
-	$(RUSTDOC) -o $(OUTPUT_DIR) foo.rs --theme $(TMPDIR)/test.css
-	$(HTMLDOCCK) $(OUTPUT_DIR) foo.rs
diff --git a/tests/run-make/rustdoc-themes/rmake.rs b/tests/run-make/rustdoc-themes/rmake.rs
new file mode 100644
index 0000000..e9da4e2
--- /dev/null
+++ b/tests/run-make/rustdoc-themes/rmake.rs
@@ -0,0 +1,31 @@
+// Test that rustdoc will properly load in a theme file and display it in the theme selector.
+
+use run_make_support::{htmldocck, rustdoc, source_path, tmp_dir};
+
+fn main() {
+    let out_dir = tmp_dir().join("rustdoc-themes");
+    let test_css = out_dir.join("test.css");
+
+    let no_script =
+        std::fs::read_to_string(source_path().join("src/librustdoc/html/static/css/noscript.css"))
+            .unwrap();
+
+    let mut test_content = String::new();
+    let mut found_begin_light = false;
+    for line in no_script.split('\n') {
+        if line == "/* Begin theme: light */" {
+            found_begin_light = true;
+        } else if line == "/* End theme: light */" {
+            break;
+        } else if found_begin_light {
+            test_content.push_str(line);
+            test_content.push('\n');
+        }
+    }
+    assert!(!test_content.is_empty());
+    std::fs::create_dir_all(&out_dir).unwrap();
+    std::fs::write(&test_css, test_content).unwrap();
+
+    rustdoc().output(&out_dir).input("foo.rs").arg("--theme").arg(&test_css).run();
+    assert!(htmldocck().arg(out_dir).arg("foo.rs").status().unwrap().success());
+}
diff --git a/tests/run-make/rustdoc-with-out-dir-option/Makefile b/tests/run-make/rustdoc-with-out-dir-option/Makefile
deleted file mode 100644
index f5d5060..0000000
--- a/tests/run-make/rustdoc-with-out-dir-option/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-include ../tools.mk
-
-OUTPUT_DIR := "$(TMPDIR)/rustdoc"
-
-all:
-	$(RUSTDOC) src/lib.rs --crate-name foobar --crate-type lib --out-dir $(OUTPUT_DIR)
-
-	$(HTMLDOCCK) $(OUTPUT_DIR) src/lib.rs
diff --git a/tests/run-make/rustdoc-with-out-dir-option/rmake.rs b/tests/run-make/rustdoc-with-out-dir-option/rmake.rs
new file mode 100644
index 0000000..8647109
--- /dev/null
+++ b/tests/run-make/rustdoc-with-out-dir-option/rmake.rs
@@ -0,0 +1,7 @@
+use run_make_support::{htmldocck, rustdoc, tmp_dir};
+
+fn main() {
+    let out_dir = tmp_dir().join("rustdoc");
+    rustdoc().input("src/lib.rs").crate_name("foobar").crate_type("lib").output(&out_dir).run();
+    assert!(htmldocck().arg(out_dir).arg("src/lib.rs").status().unwrap().success());
+}
diff --git a/tests/run-make/issue-11908/bar.rs b/tests/run-make/same-lib-two-locations-no-panic/bar.rs
similarity index 100%
rename from tests/run-make/issue-11908/bar.rs
rename to tests/run-make/same-lib-two-locations-no-panic/bar.rs
diff --git a/tests/run-make/issue-11908/foo.rs b/tests/run-make/same-lib-two-locations-no-panic/foo.rs
similarity index 100%
rename from tests/run-make/issue-11908/foo.rs
rename to tests/run-make/same-lib-two-locations-no-panic/foo.rs
diff --git a/tests/run-make/same-lib-two-locations-no-panic/rmake.rs b/tests/run-make/same-lib-two-locations-no-panic/rmake.rs
new file mode 100644
index 0000000..2900c3c
--- /dev/null
+++ b/tests/run-make/same-lib-two-locations-no-panic/rmake.rs
@@ -0,0 +1,28 @@
+// A path which contains the same rlib or dylib in two locations
+// should not cause an assertion panic in the compiler.
+// This test tries to replicate the linked issue and checks
+// if the bugged error makes a resurgence.
+
+// See https://github.com/rust-lang/rust/issues/11908
+
+//@ ignore-cross-compile
+
+use run_make_support::{dynamic_lib, rust_lib, rustc, tmp_dir};
+use std::fs;
+
+fn main() {
+    let tmp_dir_other = tmp_dir().join("other");
+
+    fs::create_dir(&tmp_dir_other);
+    rustc().input("foo.rs").crate_type("dylib").arg("-Cprefer-dynamic").run();
+    fs::rename(dynamic_lib("foo"), &tmp_dir_other);
+    rustc().input("foo.rs").crate_type("dylib").arg("-Cprefer-dynamic").run();
+    rustc().input("bar.rs").library_search_path(&tmp_dir_other).run();
+    fs::remove_dir_all(tmp_dir());
+
+    fs::create_dir_all(&tmp_dir_other);
+    rustc().input("foo.rs").crate_type("rlib").run();
+    fs::rename(rust_lib("foo"), &tmp_dir_other);
+    rustc().input("foo.rs").crate_type("rlib").run();
+    rustc().input("bar.rs").library_search_path(tmp_dir_other).run();
+}
diff --git a/tests/run-make/issue64319/bar.rs b/tests/run-make/share-generics-export-again/bar.rs
similarity index 100%
rename from tests/run-make/issue64319/bar.rs
rename to tests/run-make/share-generics-export-again/bar.rs
diff --git a/tests/run-make/issue64319/foo.rs b/tests/run-make/share-generics-export-again/foo.rs
similarity index 100%
rename from tests/run-make/issue64319/foo.rs
rename to tests/run-make/share-generics-export-again/foo.rs
diff --git a/tests/run-make/share-generics-export-again/rmake.rs b/tests/run-make/share-generics-export-again/rmake.rs
new file mode 100644
index 0000000..b9964eb
--- /dev/null
+++ b/tests/run-make/share-generics-export-again/rmake.rs
@@ -0,0 +1,45 @@
+// When crates had different optimization levels, a bug caused
+// incorrect symbol name generations. -Z share-generics could
+// also fail to re-export upstream generics on multiple compile
+// runs of the same dynamic library.
+
+// This test repeatedly compiles an rlib and a dylib with these flags
+// to check if this bug ever returns.
+
+// See https://github.com/rust-lang/rust/pull/68277
+// See https://github.com/rust-lang/rust/issues/64319
+//@ ignore-cross-compile
+
+use run_make_support::rustc;
+
+fn main() {
+    rustc().crate_type("rlib").input("foo.rs").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("3").run();
+    rustc().crate_type("rlib").input("foo.rs").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").arg("-Zshare-generics=no").run();
+    rustc().crate_type("rlib").input("foo.rs").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("rlib").input("foo.rs").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("dylib").input("bar.rs").arg("-Zshare-generics=no").run();
+    rustc().crate_type("rlib").input("foo.rs").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("dylib").input("bar.rs").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("rlib").input("foo.rs").run();
+    rustc().crate_type("dylib").input("bar.rs").run();
+    rustc().crate_type("dylib").input("bar.rs").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("1").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("1").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("1").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("2").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("2").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("2").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("3").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("3").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("3").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("s").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("s").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("s").arg("-Zshare-generics=yes").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("z").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("z").arg("-Zshare-generics=no").run();
+    rustc().crate_type("dylib").input("bar.rs").opt_level("z").arg("-Zshare-generics=yes").run();
+}
diff --git a/tests/run-make/static-unwinding/Makefile b/tests/run-make/static-unwinding/Makefile
deleted file mode 100644
index 4b093f9..0000000
--- a/tests/run-make/static-unwinding/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-# ignore-cross-compile
-# needs-unwind
-include ../tools.mk
-
-all:
-	$(RUSTC) lib.rs
-	$(RUSTC) main.rs
-	$(call RUN,main)
diff --git a/tests/run-make/static-unwinding/rmake.rs b/tests/run-make/static-unwinding/rmake.rs
new file mode 100644
index 0000000..ee3d9a3
--- /dev/null
+++ b/tests/run-make/static-unwinding/rmake.rs
@@ -0,0 +1,15 @@
+// During unwinding, an implementation of Drop is possible to clean up resources.
+// This test implements drop in both a main function and its static library.
+// If the test succeeds, a Rust program being a static library does not affect Drop implementations.
+// See https://github.com/rust-lang/rust/issues/10434
+
+//@ ignore-cross-compile
+//@ needs-unwind
+
+use run_make_support::{run, rustc};
+
+fn main() {
+    rustc().input("lib.rs").run();
+    rustc().input("main.rs").run();
+    run("main");
+}
diff --git a/tests/run-make/stdin-rustdoc/rmake.rs b/tests/run-make/stdin-rustdoc/rmake.rs
new file mode 100644
index 0000000..584a610
--- /dev/null
+++ b/tests/run-make/stdin-rustdoc/rmake.rs
@@ -0,0 +1,25 @@
+//! This test checks rustdoc `-` (stdin) handling
+
+use run_make_support::{rustdoc, tmp_dir};
+
+static INPUT: &str = r#"
+//! ```
+//! dbg!(());
+//! ```
+pub struct F;
+"#;
+
+fn main() {
+    let tmp_dir = tmp_dir();
+    let out_dir = tmp_dir.join("doc");
+
+    // rustdoc -
+    rustdoc().arg("-").out_dir(&out_dir).stdin(INPUT).run();
+    assert!(out_dir.join("rust_out/struct.F.html").try_exists().unwrap());
+
+    // rustdoc --test -
+    rustdoc().arg("--test").arg("-").stdin(INPUT).run();
+
+    // rustdoc file.rs -
+    rustdoc().arg("file.rs").arg("-").run_fail();
+}
diff --git a/tests/rustdoc-ui/issues/issue-91713.stdout b/tests/rustdoc-ui/issues/issue-91713.stdout
index bbea7e5..cc3c838 100644
--- a/tests/rustdoc-ui/issues/issue-91713.stdout
+++ b/tests/rustdoc-ui/issues/issue-91713.stdout
@@ -1,6 +1,7 @@
 Available passes for running rustdoc:
 check-custom-code-classes - check for custom code classes without the feature-gate enabled
 check_doc_test_visibility - run various visibility-related lints on doctests
+strip-aliased-non-local - strips all non-local private aliased items from the output
         strip-hidden - strips all `#[doc(hidden)]` items from the output
        strip-private - strips all private items from a crate which cannot be seen externally, implies strip-priv-imports
   strip-priv-imports - strips all private import statements (`use`, `extern crate`) from a crate
@@ -14,6 +15,7 @@
 check-custom-code-classes
  collect-trait-impls
 check_doc_test_visibility
+strip-aliased-non-local
         strip-hidden  (when not --document-hidden-items)
        strip-private  (when not --document-private-items)
   strip-priv-imports  (when --document-private-items)
diff --git a/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs b/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs
index f4e020b..d85129a 100644
--- a/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs
+++ b/tests/rustdoc/auxiliary/cross_crate_generic_typedef.rs
@@ -3,3 +3,8 @@
 }
 
 pub type InlineU64 = InlineOne<u64>;
+
+pub enum GenericEnum<T> {
+   Variant(T),
+   Variant2(T, T),
+}
diff --git a/tests/rustdoc/inline_cross/assoc-const-equality.rs b/tests/rustdoc/inline_cross/assoc-const-equality.rs
index 89ed808..cdf7438 100644
--- a/tests/rustdoc/inline_cross/assoc-const-equality.rs
+++ b/tests/rustdoc/inline_cross/assoc-const-equality.rs
@@ -1,5 +1,6 @@
 //@ aux-crate:assoc_const_equality=assoc-const-equality.rs
 //@ edition:2021
+//@ ignore-test (FIXME: #125092)
 
 #![crate_name = "user"]
 
diff --git a/tests/rustdoc/inline_cross/issue-76736-2.rs b/tests/rustdoc/inline_cross/issue-76736-2.rs
index 83529dd..d4e6a69 100644
--- a/tests/rustdoc/inline_cross/issue-76736-2.rs
+++ b/tests/rustdoc/inline_cross/issue-76736-2.rs
@@ -1,6 +1,8 @@
 //@ aux-build:issue-76736-1.rs
 //@ aux-build:issue-76736-2.rs
 
+// https://github.com/rust-lang/rust/issues/124635
+
 #![crate_name = "foo"]
 #![feature(rustc_private)]
 
@@ -8,9 +10,9 @@
 extern crate issue_76736_2;
 
 // @has foo/struct.Foo.html
-// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult'
+// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult'
 pub struct Foo;
 
 // @has foo/struct.Bar.html
-// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult'
+// @!has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult'
 pub use issue_76736_2::Bar;
diff --git a/tests/rustdoc/inline_cross/issue-76736-4.rs b/tests/rustdoc/inline_cross/issue-76736-4.rs
new file mode 100644
index 0000000..297657e
--- /dev/null
+++ b/tests/rustdoc/inline_cross/issue-76736-4.rs
@@ -0,0 +1,19 @@
+//@ aux-build:issue-76736-1.rs
+//@ aux-build:issue-76736-2.rs
+
+// https://github.com/rust-lang/rust/issues/124635
+
+#![crate_name = "foo"]
+#![feature(rustc_private, staged_api)]
+#![unstable(feature = "rustc_private", issue = "none")]
+
+extern crate issue_76736_1;
+extern crate issue_76736_2;
+
+// @has foo/struct.Foo.html
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult'
+pub struct Foo;
+
+// @has foo/struct.Bar.html
+// @has - '//*[@class="impl"]//h3[@class="code-header"]' 'MaybeResult'
+pub use issue_76736_2::Bar;
diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-negative.negative.html b/tests/rustdoc/notable-trait/doc-notable_trait-negative.negative.html
new file mode 100644
index 0000000..6f19558
--- /dev/null
+++ b/tests/rustdoc/notable-trait/doc-notable_trait-negative.negative.html
@@ -0,0 +1 @@
+<script type="text/json" id="notable-traits-data">{"Negative":"&lt;/code&gt;&lt;/pre&gt;"}</script>
\ No newline at end of file
diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-negative.positive.html b/tests/rustdoc/notable-trait/doc-notable_trait-negative.positive.html
new file mode 100644
index 0000000..a3d0fed
--- /dev/null
+++ b/tests/rustdoc/notable-trait/doc-notable_trait-negative.positive.html
@@ -0,0 +1 @@
+<script type="text/json" id="notable-traits-data">{"Positive":"&lt;h3&gt;Notable traits for &lt;code&gt;&lt;a class=\"struct\" href=\"struct.Positive.html\" title=\"struct doc_notable_trait_negative::Positive\"&gt;Positive&lt;/a&gt;&lt;/code&gt;&lt;/h3&gt;&lt;pre&gt;&lt;code&gt;&lt;div class=\"where\"&gt;impl &lt;a class=\"trait\" href=\"trait.SomeTrait.html\" title=\"trait doc_notable_trait_negative::SomeTrait\"&gt;SomeTrait&lt;/a&gt; for &lt;a class=\"struct\" href=\"struct.Positive.html\" title=\"struct doc_notable_trait_negative::Positive\"&gt;Positive&lt;/a&gt;&lt;/div&gt;"}</script>
\ No newline at end of file
diff --git a/tests/rustdoc/notable-trait/doc-notable_trait-negative.rs b/tests/rustdoc/notable-trait/doc-notable_trait-negative.rs
new file mode 100644
index 0000000..2bbe0a3
--- /dev/null
+++ b/tests/rustdoc/notable-trait/doc-notable_trait-negative.rs
@@ -0,0 +1,22 @@
+#![feature(doc_notable_trait, negative_impls)]
+
+#[doc(notable_trait)]
+pub trait SomeTrait {}
+
+pub struct Positive;
+impl SomeTrait for Positive {}
+
+pub struct Negative;
+impl !SomeTrait for Negative {}
+
+// @has doc_notable_trait_negative/fn.positive.html
+// @snapshot positive - '//script[@id="notable-traits-data"]'
+pub fn positive() -> Positive {
+    todo!()
+}
+
+// @has doc_notable_trait_negative/fn.negative.html
+// @count - '//script[@id="notable-traits-data"]' 0
+pub fn negative() -> Negative {
+    &[]
+}
diff --git a/tests/rustdoc/private-non-local-fields-2.rs b/tests/rustdoc/private-non-local-fields-2.rs
new file mode 100644
index 0000000..615b957
--- /dev/null
+++ b/tests/rustdoc/private-non-local-fields-2.rs
@@ -0,0 +1,11 @@
+//! This test makes sure that with never show the inner fields in the
+//! aliased type view of type alias.
+
+//@ compile-flags: -Z unstable-options --document-private-items
+
+#![crate_name = "foo"]
+
+use std::collections::BTreeMap;
+
+// @has 'foo/type.FooBar.html' '//*[@class="rust item-decl"]/code' 'struct FooBar { /* private fields */ }'
+pub type FooBar = BTreeMap<u32, String>;
diff --git a/tests/rustdoc/private-non-local-fields.rs b/tests/rustdoc/private-non-local-fields.rs
new file mode 100644
index 0000000..7922ce0
--- /dev/null
+++ b/tests/rustdoc/private-non-local-fields.rs
@@ -0,0 +1,9 @@
+//! This test makes sure that with never show the inner fields in the
+//! aliased type view of type alias.
+
+#![crate_name = "foo"]
+
+use std::collections::BTreeMap;
+
+// @has 'foo/type.FooBar.html' '//*[@class="rust item-decl"]/code' 'struct FooBar { /* private fields */ }'
+pub type FooBar = BTreeMap<u32, String>;
diff --git a/tests/rustdoc/typedef-inner-variants.rs b/tests/rustdoc/typedef-inner-variants.rs
index d87a1cb..0e65fda 100644
--- a/tests/rustdoc/typedef-inner-variants.rs
+++ b/tests/rustdoc/typedef-inner-variants.rs
@@ -117,3 +117,10 @@
 // @count - '//*[@id="variants"]' 0
 // @count - '//*[@id="fields"]' 1
 pub use cross_crate_generic_typedef::InlineU64;
+
+// @has 'inner_variants/type.InlineEnum.html'
+// @count - '//*[@id="aliased-type"]' 1
+// @count - '//*[@id="variants"]' 1
+// @count - '//*[@id="fields"]' 0
+// @count - '//*[@class="variant"]' 2
+pub type InlineEnum = cross_crate_generic_typedef::GenericEnum<i32>;
diff --git a/tests/ui-fulldeps/pprust-expr-roundtrip.rs b/tests/ui-fulldeps/pprust-expr-roundtrip.rs
index 475a69f..2b1fec9 100644
--- a/tests/ui-fulldeps/pprust-expr-roundtrip.rs
+++ b/tests/ui-fulldeps/pprust-expr-roundtrip.rs
@@ -180,7 +180,10 @@
             18 => {
                 let pat =
                     P(Pat { id: DUMMY_NODE_ID, kind: PatKind::Wild, span: DUMMY_SP, tokens: None });
-                iter_exprs(depth - 1, &mut |e| g(ExprKind::Let(pat.clone(), e, DUMMY_SP, None)))
+                iter_exprs(
+                    depth - 1,
+                    &mut |e| g(ExprKind::Let(pat.clone(), e, DUMMY_SP, Recovered::No))
+                )
             }
             _ => panic!("bad counter value in iter_exprs"),
         }
diff --git a/tests/ui-fulldeps/stable-mir/check_abi.rs b/tests/ui-fulldeps/stable-mir/check_abi.rs
index 74801e0..359dd414 100644
--- a/tests/ui-fulldeps/stable-mir/check_abi.rs
+++ b/tests/ui-fulldeps/stable-mir/check_abi.rs
@@ -99,7 +99,7 @@
     assert_matches!(layout.variants, VariantsShape::Multiple { .. })
 }
 
-/// Check the niche information about: `NonZeroU8`
+/// Checks the niche information about `NonZero<u8>`.
 fn check_niche(abi: &ArgAbi) {
     assert!(abi.ty.kind().is_struct());
     assert_matches!(abi.mode, PassMode::Direct { .. });
@@ -150,12 +150,12 @@
         #![feature(c_variadic)]
         #![allow(unused_variables)]
 
-        use std::num::NonZeroU8;
+        use std::num::NonZero;
 
         pub fn fn_abi(
             ignore: [u8; 0],
             primitive: char,
-            niche: NonZeroU8,
+            niche: NonZero<u8>,
         ) -> Result<usize, &'static str> {{
                 // We only care about the signature.
                 todo!()
diff --git a/tests/ui/abi/debug.stderr b/tests/ui/abi/debug.stderr
index 00fc7d1..7365839 100644
--- a/tests/ui/abi/debug.stderr
+++ b/tests/ui/abi/debug.stderr
@@ -576,7 +576,9 @@
                            },
                            abi: Scalar(
                                Initialized {
-                                   value: F32,
+                                   value: Float(
+                                       F32,
+                                   ),
                                    valid_range: $FULL,
                                },
                            ),
diff --git a/tests/ui/abi/extern/auxiliary/extern-crosscrate-source.rs b/tests/ui/abi/extern/auxiliary/extern-crosscrate-source.rs
index 9c61518..6b21877 100644
--- a/tests/ui/abi/extern/auxiliary/extern-crosscrate-source.rs
+++ b/tests/ui/abi/extern/auxiliary/extern-crosscrate-source.rs
@@ -1,28 +1,21 @@
 #![crate_name = "externcallback"]
 #![crate_type = "lib"]
-#![feature(rustc_private)]
 
-extern crate libc;
-
-pub mod rustrt {
-    extern crate libc;
-
-    #[link(name = "rust_test_helpers", kind = "static")]
-    extern "C" {
-        pub fn rust_dbg_call(
-            cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t,
-            data: libc::uintptr_t,
-        ) -> libc::uintptr_t;
-    }
+#[link(name = "rust_test_helpers", kind = "static")]
+extern "C" {
+    pub fn rust_dbg_call(
+        cb: extern "C" fn(u64) -> u64,
+        data: u64,
+    ) -> u64;
 }
 
-pub fn fact(n: libc::uintptr_t) -> libc::uintptr_t {
+pub fn fact(n: u64) -> u64 {
     unsafe {
         println!("n = {}", n);
-        rustrt::rust_dbg_call(cb, n)
+        rust_dbg_call(cb, n)
     }
 }
 
-pub extern "C" fn cb(data: libc::uintptr_t) -> libc::uintptr_t {
+pub extern "C" fn cb(data: u64) -> u64 {
     if data == 1 { data } else { fact(data - 1) * data }
 }
diff --git a/tests/ui/abi/extern/extern-call-deep.rs b/tests/ui/abi/extern/extern-call-deep.rs
index 062e70b..40457ae 100644
--- a/tests/ui/abi/extern/extern-call-deep.rs
+++ b/tests/ui/abi/extern/extern-call-deep.rs
@@ -1,35 +1,27 @@
 //@ run-pass
 //@ ignore-emscripten blows the JS stack
 
-#![feature(rustc_private)]
-
-extern crate libc;
-
-mod rustrt {
-    extern crate libc;
-
-    #[link(name = "rust_test_helpers", kind = "static")]
-    extern "C" {
-        pub fn rust_dbg_call(
-            cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t,
-            data: libc::uintptr_t,
-        ) -> libc::uintptr_t;
-    }
+#[link(name = "rust_test_helpers", kind = "static")]
+extern "C" {
+    pub fn rust_dbg_call(
+        cb: extern "C" fn(u64) -> u64,
+        data: u64,
+    ) -> u64;
 }
 
-extern "C" fn cb(data: libc::uintptr_t) -> libc::uintptr_t {
+extern "C" fn cb(data: u64) -> u64 {
     if data == 1 { data } else { count(data - 1) + 1 }
 }
 
-fn count(n: libc::uintptr_t) -> libc::uintptr_t {
+fn count(n: u64) -> u64 {
     unsafe {
         println!("n = {}", n);
-        rustrt::rust_dbg_call(cb, n)
+        rust_dbg_call(cb, n)
     }
 }
 
 pub fn main() {
     let result = count(1000);
-    println!("result = {}", result);
+    println!("result = {:?}", result);
     assert_eq!(result, 1000);
 }
diff --git a/tests/ui/abi/extern/extern-call-deep2.rs b/tests/ui/abi/extern/extern-call-deep2.rs
index c021bc2..91ca28d 100644
--- a/tests/ui/abi/extern/extern-call-deep2.rs
+++ b/tests/ui/abi/extern/extern-call-deep2.rs
@@ -1,31 +1,24 @@
 //@ run-pass
-#![allow(unused_must_use)]
 //@ needs-threads
-#![feature(rustc_private)]
 
-extern crate libc;
 use std::thread;
 
-mod rustrt {
-    extern crate libc;
-
-    #[link(name = "rust_test_helpers", kind = "static")]
-    extern "C" {
-        pub fn rust_dbg_call(
-            cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t,
-            data: libc::uintptr_t,
-        ) -> libc::uintptr_t;
-    }
+#[link(name = "rust_test_helpers", kind = "static")]
+extern "C" {
+    pub fn rust_dbg_call(
+        cb: extern "C" fn(u64) -> u64,
+        data: u64,
+    ) -> u64;
 }
 
-extern "C" fn cb(data: libc::uintptr_t) -> libc::uintptr_t {
-    if data == 1 { data } else { count(data - 1) + 1 }
+extern "C" fn cb(data: u64) -> u64 {
+    if data == 1 { data } else { count(data - 1 ) + 1 }
 }
 
-fn count(n: libc::uintptr_t) -> libc::uintptr_t {
+fn count(n: u64) -> u64 {
     unsafe {
         println!("n = {}", n);
-        rustrt::rust_dbg_call(cb, n)
+        rust_dbg_call(cb, n)
     }
 }
 
@@ -37,5 +30,5 @@
         println!("result = {}", result);
         assert_eq!(result, 1000);
     })
-    .join();
+    .join().unwrap();
 }
diff --git a/tests/ui/abi/extern/extern-call-indirect.rs b/tests/ui/abi/extern/extern-call-indirect.rs
index 18fb07d..ef1e8ae 100644
--- a/tests/ui/abi/extern/extern-call-indirect.rs
+++ b/tests/ui/abi/extern/extern-call-indirect.rs
@@ -1,29 +1,21 @@
 //@ run-pass
 
-#![feature(rustc_private)]
-
-extern crate libc;
-
-mod rustrt {
-    extern crate libc;
-
-    #[link(name = "rust_test_helpers", kind = "static")]
-    extern "C" {
-        pub fn rust_dbg_call(
-            cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t,
-            data: libc::uintptr_t,
-        ) -> libc::uintptr_t;
-    }
+#[link(name = "rust_test_helpers", kind = "static")]
+extern "C" {
+    pub fn rust_dbg_call(
+        cb: extern "C" fn(u64) -> u64,
+        data: u64,
+    ) -> u64;
 }
 
-extern "C" fn cb(data: libc::uintptr_t) -> libc::uintptr_t {
+extern "C" fn cb(data: u64) -> u64 {
     if data == 1 { data } else { fact(data - 1) * data }
 }
 
-fn fact(n: libc::uintptr_t) -> libc::uintptr_t {
+fn fact(n: u64) -> u64 {
     unsafe {
         println!("n = {}", n);
-        rustrt::rust_dbg_call(cb, n)
+        rust_dbg_call(cb, n)
     }
 }
 
diff --git a/tests/ui/abi/extern/extern-call-scrub.rs b/tests/ui/abi/extern/extern-call-scrub.rs
index 7edf897..7df3a8f 100644
--- a/tests/ui/abi/extern/extern-call-scrub.rs
+++ b/tests/ui/abi/extern/extern-call-scrub.rs
@@ -1,35 +1,27 @@
 //@ run-pass
-#![allow(unused_must_use)]
+//@ needs-threads
 // This time we're testing repeatedly going up and down both stacks to
 // make sure the stack pointers are maintained properly in both
 // directions
 
-//@ needs-threads
-#![feature(rustc_private)]
-
-extern crate libc;
 use std::thread;
 
-mod rustrt {
-    extern crate libc;
-
-    #[link(name = "rust_test_helpers", kind = "static")]
-    extern "C" {
-        pub fn rust_dbg_call(
-            cb: extern "C" fn(libc::uintptr_t) -> libc::uintptr_t,
-            data: libc::uintptr_t,
-        ) -> libc::uintptr_t;
-    }
+#[link(name = "rust_test_helpers", kind = "static")]
+extern "C" {
+    pub fn rust_dbg_call(
+        cb: extern "C" fn(u64) -> u64,
+        data: u64,
+    ) -> u64;
 }
 
-extern "C" fn cb(data: libc::uintptr_t) -> libc::uintptr_t {
+extern "C" fn cb(data: u64) -> u64 {
     if data == 1 { data } else { count(data - 1) + count(data - 1) }
 }
 
-fn count(n: libc::uintptr_t) -> libc::uintptr_t {
+fn count(n: u64) -> u64 {
     unsafe {
         println!("n = {}", n);
-        rustrt::rust_dbg_call(cb, n)
+        rust_dbg_call(cb, n)
     }
 }
 
@@ -41,5 +33,5 @@
         println!("result = {}", result);
         assert_eq!(result, 2048);
     })
-    .join();
+    .join().unwrap();
 }
diff --git a/tests/ui/abi/extern/extern-crosscrate.rs b/tests/ui/abi/extern/extern-crosscrate.rs
index c283cbe..b467d99 100644
--- a/tests/ui/abi/extern/extern-crosscrate.rs
+++ b/tests/ui/abi/extern/extern-crosscrate.rs
@@ -1,15 +1,12 @@
 //@ run-pass
 //@ aux-build:extern-crosscrate-source.rs
 
-#![feature(rustc_private)]
-
 extern crate externcallback;
-extern crate libc;
 
-fn fact(n: libc::uintptr_t) -> libc::uintptr_t {
+fn fact(n: u64) -> u64 {
     unsafe {
-        println!("n = {}", n);
-        externcallback::rustrt::rust_dbg_call(externcallback::cb, n)
+        println!("n = {:?}", n);
+        externcallback::rust_dbg_call(externcallback::cb, n)
     }
 }
 
diff --git a/tests/ui/abi/foreign/foreign-call-no-runtime.rs b/tests/ui/abi/foreign/foreign-call-no-runtime.rs
deleted file mode 100644
index fccd62b..0000000
--- a/tests/ui/abi/foreign/foreign-call-no-runtime.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-//@ run-pass
-//@ needs-threads
-
-#![feature(rustc_private)]
-
-extern crate libc;
-
-use std::mem;
-use std::thread;
-
-#[link(name = "rust_test_helpers", kind = "static")]
-extern "C" {
-    fn rust_dbg_call(cb: extern "C" fn(libc::uintptr_t), data: libc::uintptr_t) -> libc::uintptr_t;
-}
-
-pub fn main() {
-    unsafe {
-        thread::spawn(move || {
-            let i: isize = 100;
-            rust_dbg_call(callback_isize, mem::transmute(&i));
-        })
-        .join()
-        .unwrap();
-
-        thread::spawn(move || {
-            let i: i32 = 100;
-            rust_dbg_call(callback_i32, mem::transmute(&i));
-        })
-        .join()
-        .unwrap();
-
-        thread::spawn(move || {
-            let i: i64 = 100;
-            rust_dbg_call(callback_i64, mem::transmute(&i));
-        })
-        .join()
-        .unwrap();
-    }
-}
-
-extern "C" fn callback_isize(data: libc::uintptr_t) {
-    unsafe {
-        let data = data as *const isize;
-        assert_eq!(*data, 100);
-    }
-}
-
-extern "C" fn callback_i64(data: libc::uintptr_t) {
-    unsafe {
-        let data = data as *const i64;
-        assert_eq!(*data, 100);
-    }
-}
-
-extern "C" fn callback_i32(data: libc::uintptr_t) {
-    unsafe {
-        let data = data as *const i32;
-        assert_eq!(*data, 100);
-    }
-}
diff --git a/tests/ui/empty_global_asm.rs b/tests/ui/asm/empty_global_asm.rs
similarity index 100%
rename from tests/ui/empty_global_asm.rs
rename to tests/ui/asm/empty_global_asm.rs
diff --git a/tests/ui/simple_global_asm.rs b/tests/ui/asm/simple_global_asm.rs
similarity index 100%
rename from tests/ui/simple_global_asm.rs
rename to tests/ui/asm/simple_global_asm.rs
diff --git a/tests/ui/associated-consts/issue-105330.rs b/tests/ui/associated-consts/issue-105330.rs
index fb2169a..959bb4f 100644
--- a/tests/ui/associated-consts/issue-105330.rs
+++ b/tests/ui/associated-consts/issue-105330.rs
@@ -11,7 +11,6 @@
 fn foo<A: TraitWAssocConst<A=32>>() { //~ ERROR E0658
     foo::<Demo>()();
     //~^ ERROR is not satisfied
-    //~| ERROR type mismatch
     //~| ERROR expected function, found `()`
 }
 
@@ -19,6 +18,5 @@
     //~^ ERROR E0658
     //~| ERROR E0131
     foo::<Demo>();
-    //~^ ERROR type mismatch
-    //~| ERROR is not satisfied
+    //~^ ERROR is not satisfied
 }
diff --git a/tests/ui/associated-consts/issue-105330.stderr b/tests/ui/associated-consts/issue-105330.stderr
index bde3675..7252719 100644
--- a/tests/ui/associated-consts/issue-105330.stderr
+++ b/tests/ui/associated-consts/issue-105330.stderr
@@ -26,7 +26,7 @@
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: associated const equality is incomplete
-  --> $DIR/issue-105330.rs:18:29
+  --> $DIR/issue-105330.rs:17:29
    |
 LL | fn main<A: TraitWAssocConst<A=32>>() {
    |                             ^^^^
@@ -44,7 +44,7 @@
    = note: `impl Trait` is only allowed in arguments and return types of functions and methods
 
 error[E0131]: `main` function is not allowed to have generic parameters
-  --> $DIR/issue-105330.rs:18:8
+  --> $DIR/issue-105330.rs:17:8
    |
 LL | fn main<A: TraitWAssocConst<A=32>>() {
    |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `main` cannot have generic parameters
@@ -61,20 +61,6 @@
 LL | fn foo<A: TraitWAssocConst<A=32>>() {
    |           ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
 
-error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
-  --> $DIR/issue-105330.rs:12:11
-   |
-LL |     foo::<Demo>()();
-   |           ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
-   |
-   = note: expected constant `32`
-              found constant `<Demo as TraitWAssocConst>::A`
-note: required by a bound in `foo`
-  --> $DIR/issue-105330.rs:11:28
-   |
-LL | fn foo<A: TraitWAssocConst<A=32>>() {
-   |                            ^^^^ required by this bound in `foo`
-
 error[E0618]: expected function, found `()`
   --> $DIR/issue-105330.rs:12:5
    |
@@ -86,7 +72,7 @@
    |     call expression requires function
 
 error[E0277]: the trait bound `Demo: TraitWAssocConst` is not satisfied
-  --> $DIR/issue-105330.rs:21:11
+  --> $DIR/issue-105330.rs:20:11
    |
 LL |     foo::<Demo>();
    |           ^^^^ the trait `TraitWAssocConst` is not implemented for `Demo`
@@ -97,21 +83,7 @@
 LL | fn foo<A: TraitWAssocConst<A=32>>() {
    |           ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo`
 
-error[E0271]: type mismatch resolving `<Demo as TraitWAssocConst>::A == 32`
-  --> $DIR/issue-105330.rs:21:11
-   |
-LL |     foo::<Demo>();
-   |           ^^^^ expected `32`, found `<Demo as TraitWAssocConst>::A`
-   |
-   = note: expected constant `32`
-              found constant `<Demo as TraitWAssocConst>::A`
-note: required by a bound in `foo`
-  --> $DIR/issue-105330.rs:11:28
-   |
-LL | fn foo<A: TraitWAssocConst<A=32>>() {
-   |                            ^^^^ required by this bound in `foo`
+error: aborting due to 9 previous errors
 
-error: aborting due to 11 previous errors
-
-Some errors have detailed explanations: E0131, E0271, E0277, E0404, E0562, E0618, E0658.
+Some errors have detailed explanations: E0131, E0277, E0404, E0562, E0618, E0658.
 For more information about an error, try `rustc --explain E0131`.
diff --git a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr
index 77fbaf5..bf53089 100644
--- a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr
+++ b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.next.stderr
@@ -1,8 +1,11 @@
-error: the type `Foo::Bar<Vec<[u32]>>` is not well-formed
-  --> $DIR/wf-check-skipped.rs:17:14
+error[E0277]: the size for values of type `[u32]` cannot be known at compilation time
+  --> $DIR/wf-check-skipped.rs:17:25
    |
 LL | fn main() -> Foo::Bar::<Vec<[u32]>> {}
-   |              ^^^^^^^^^^^^^^^^^^^^^^
+   |                         ^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[u32]`
 
 error: aborting due to 1 previous error
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs
index 5b812a2..52df4ef 100644
--- a/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs
+++ b/tests/ui/associated-inherent-types/bugs/wf-check-skipped.rs
@@ -15,4 +15,4 @@
 }
 
 fn main() -> Foo::Bar::<Vec<[u32]>> {}
-//[next]~^ ERROR the type `Foo::Bar<Vec<[u32]>>` is not well-formed
+//[next]~^ ERROR the size for values of type `[u32]` cannot be known at compilation time
diff --git a/tests/ui/associated-types/associated-types-eq-2.rs b/tests/ui/associated-types/associated-types-eq-2.rs
index d71697e..43b0208 100644
--- a/tests/ui/associated-types/associated-types-eq-2.rs
+++ b/tests/ui/associated-types/associated-types-eq-2.rs
@@ -4,7 +4,7 @@
 struct Bar;
 struct Qux;
 
-// Tests for a a non generic trait
+// Tests for a non generic trait
 pub trait Tr1 {
     type A;
     fn boo(&self) -> <Self as Tr1>::A;
diff --git a/tests/ui/associated-types/bound-lifetime-constrained.ok.stderr b/tests/ui/associated-types/bound-lifetime-constrained.ok.stderr
new file mode 100644
index 0000000..9082044
--- /dev/null
+++ b/tests/ui/associated-types/bound-lifetime-constrained.ok.stderr
@@ -0,0 +1,8 @@
+error: fatal error triggered by #[rustc_error]
+  --> $DIR/bound-lifetime-constrained.rs:48:1
+   |
+LL | fn main() { }
+   | ^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/associated-types/bound-lifetime-constrained.rs b/tests/ui/associated-types/bound-lifetime-constrained.rs
index 880d350..1dc3b2f 100644
--- a/tests/ui/associated-types/bound-lifetime-constrained.rs
+++ b/tests/ui/associated-types/bound-lifetime-constrained.rs
@@ -1,4 +1,4 @@
-//@ revisions: func object clause
+//@ revisions: func object clause ok
 
 #![allow(dead_code)]
 #![feature(rustc_attrs)]
diff --git a/tests/ui/async-await/async-block-control-flow-static-semantics.rs b/tests/ui/async-await/async-block-control-flow-static-semantics.rs
index 0ef7cb7..6e04c53 100644
--- a/tests/ui/async-await/async-block-control-flow-static-semantics.rs
+++ b/tests/ui/async-await/async-block-control-flow-static-semantics.rs
@@ -29,14 +29,14 @@
 
 fn no_break_in_async_block() {
     async {
-        break 0u8; //~ ERROR `break` inside of an `async` block
+        break 0u8; //~ ERROR `break` inside `async` block
     };
 }
 
 fn no_break_in_async_block_even_with_outer_loop() {
     loop {
         async {
-            break 0u8; //~ ERROR `break` inside of an `async` block
+            break 0u8; //~ ERROR `break` inside `async` block
         };
     }
 }
diff --git a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr
index c89671c..ce0d003 100644
--- a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr
+++ b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr
@@ -1,18 +1,18 @@
-error[E0267]: `break` inside of an `async` block
+error[E0267]: `break` inside `async` block
   --> $DIR/async-block-control-flow-static-semantics.rs:32:9
    |
 LL | /     async {
 LL | |         break 0u8;
-   | |         ^^^^^^^^^ cannot `break` inside of an `async` block
+   | |         ^^^^^^^^^ cannot `break` inside `async` block
 LL | |     };
    | |_____- enclosing `async` block
 
-error[E0267]: `break` inside of an `async` block
+error[E0267]: `break` inside `async` block
   --> $DIR/async-block-control-flow-static-semantics.rs:39:13
    |
 LL | /         async {
 LL | |             break 0u8;
-   | |             ^^^^^^^^^ cannot `break` inside of an `async` block
+   | |             ^^^^^^^^^ cannot `break` inside `async` block
 LL | |         };
    | |_________- enclosing `async` block
 
diff --git a/tests/ui/async-await/async-closures/ambiguous-arg.rs b/tests/ui/async-await/async-closures/ambiguous-arg.rs
new file mode 100644
index 0000000..d76a1cf
--- /dev/null
+++ b/tests/ui/async-await/async-closures/ambiguous-arg.rs
@@ -0,0 +1,15 @@
+//@ edition:2021
+
+// Regression test for #123901. We previously ICE'd as we silently
+// swallowed an in the `ExprUseVisitor`.
+
+#![feature(async_closure)]
+
+pub fn test(test: &u64, temp: &u64) {
+    async |check, a, b| {
+        //~^ ERROR type annotations needed
+        temp.abs_diff(12);
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/async-closures/ambiguous-arg.stderr b/tests/ui/async-await/async-closures/ambiguous-arg.stderr
new file mode 100644
index 0000000..01f72e9
--- /dev/null
+++ b/tests/ui/async-await/async-closures/ambiguous-arg.stderr
@@ -0,0 +1,13 @@
+error[E0282]: type annotations needed
+  --> $DIR/ambiguous-arg.rs:9:25
+   |
+LL |       async |check, a, b| {
+   |  _________________________^
+LL | |
+LL | |         temp.abs_diff(12);
+LL | |     };
+   | |_____^ cannot infer type
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr
index 70cd9f9..649a868 100644
--- a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr
+++ b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr
@@ -11,6 +11,9 @@
 error[E0308]: mismatched types
   --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:12:9
    |
+LL |     call(|| -> Option<()> {
+   |                ---------- expected `Option<()>` because of return type
+...
 LL |         true
    |         ^^^^ expected `Option<()>`, found `bool`
    |
diff --git a/tests/ui/attributes/nonterminal-expansion.rs b/tests/ui/attributes/nonterminal-expansion.rs
index 6db7aea..1b2e92a 100644
--- a/tests/ui/attributes/nonterminal-expansion.rs
+++ b/tests/ui/attributes/nonterminal-expansion.rs
@@ -5,7 +5,7 @@
 macro_rules! pass_nonterminal {
     ($n:expr) => {
         #[repr(align($n))]
-        //~^ ERROR expected unsuffixed literal or identifier, found `n!()`
+        //~^ ERROR expected unsuffixed literal, found `n!()`
         struct S;
     };
 }
diff --git a/tests/ui/attributes/nonterminal-expansion.stderr b/tests/ui/attributes/nonterminal-expansion.stderr
index 7854149..b640575 100644
--- a/tests/ui/attributes/nonterminal-expansion.stderr
+++ b/tests/ui/attributes/nonterminal-expansion.stderr
@@ -1,4 +1,4 @@
-error: expected unsuffixed literal or identifier, found `n!()`
+error: expected unsuffixed literal, found `n!()`
   --> $DIR/nonterminal-expansion.rs:7:22
    |
 LL |         #[repr(align($n))]
diff --git a/tests/ui/attributes/rustc_confusables_std_cases.stderr b/tests/ui/attributes/rustc_confusables_std_cases.stderr
index 45d571f..f4b6947 100644
--- a/tests/ui/attributes/rustc_confusables_std_cases.stderr
+++ b/tests/ui/attributes/rustc_confusables_std_cases.stderr
@@ -26,6 +26,14 @@
 LL |     x.push(1);
    |       ^^^^ method not found in `VecDeque<_>`
    |
+note: there's an earlier shadowed binding `x` of type `Vec<_>` that has method `push` available
+  --> $DIR/rustc_confusables_std_cases.rs:8:9
+   |
+LL |     let mut x = Vec::new();
+   |         ^^^^^ `x` of type `Vec<_>` that has method `push` defined earlier here
+...
+LL |     let mut x = VecDeque::new();
+   |         ----- earlier `x` shadowed here with type `VecDeque`
 help: you might have meant to use `push_back`
    |
 LL |     x.push_back(1);
diff --git a/tests/ui/backtrace-apple-no-dsymutil.rs b/tests/ui/backtrace/apple-no-dsymutil.rs
similarity index 100%
rename from tests/ui/backtrace-apple-no-dsymutil.rs
rename to tests/ui/backtrace/apple-no-dsymutil.rs
diff --git a/tests/ui/debuginfo/auxiliary/dylib-dep-helper-aux.rs b/tests/ui/backtrace/auxiliary/dylib-dep-helper-aux.rs
similarity index 100%
rename from tests/ui/debuginfo/auxiliary/dylib-dep-helper-aux.rs
rename to tests/ui/backtrace/auxiliary/dylib-dep-helper-aux.rs
diff --git a/tests/ui/debuginfo/auxiliary/dylib-dep-helper.rs b/tests/ui/backtrace/auxiliary/dylib-dep-helper.rs
similarity index 100%
rename from tests/ui/debuginfo/auxiliary/dylib-dep-helper.rs
rename to tests/ui/backtrace/auxiliary/dylib-dep-helper.rs
diff --git a/tests/ui/debuginfo/auxiliary/line-tables-only-helper.rs b/tests/ui/backtrace/auxiliary/line-tables-only-helper.rs
similarity index 100%
rename from tests/ui/debuginfo/auxiliary/line-tables-only-helper.rs
rename to tests/ui/backtrace/auxiliary/line-tables-only-helper.rs
diff --git a/tests/ui/backtrace.rs b/tests/ui/backtrace/backtrace.rs
similarity index 100%
rename from tests/ui/backtrace.rs
rename to tests/ui/backtrace/backtrace.rs
diff --git a/tests/ui/debuginfo/backtrace-dylib-dep.rs b/tests/ui/backtrace/dylib-dep.rs
similarity index 100%
rename from tests/ui/debuginfo/backtrace-dylib-dep.rs
rename to tests/ui/backtrace/dylib-dep.rs
diff --git a/tests/ui/debuginfo/backtrace-line-tables-only.rs b/tests/ui/backtrace/line-tables-only.rs
similarity index 100%
rename from tests/ui/debuginfo/backtrace-line-tables-only.rs
rename to tests/ui/backtrace/line-tables-only.rs
diff --git a/tests/ui/std-backtrace.rs b/tests/ui/backtrace/std-backtrace.rs
similarity index 100%
rename from tests/ui/std-backtrace.rs
rename to tests/ui/backtrace/std-backtrace.rs
diff --git a/tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr b/tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr
index aacf178..6cd64c5 100644
--- a/tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr
+++ b/tests/ui/borrowck/two-phase-activation-sharing-interference.nll_target.stderr
@@ -1,5 +1,5 @@
 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
-  --> $DIR/two-phase-activation-sharing-interference.rs:28:15
+  --> $DIR/two-phase-activation-sharing-interference.rs:29:15
    |
 LL |     let y = &mut x;
    |             ------ mutable borrow occurs here
@@ -10,7 +10,7 @@
    |     ------- mutable borrow later used here
 
 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
-  --> $DIR/two-phase-activation-sharing-interference.rs:36:13
+  --> $DIR/two-phase-activation-sharing-interference.rs:37:13
    |
 LL |     let y = &mut x;
    |             ------ mutable borrow occurs here
@@ -32,7 +32,7 @@
    |     ------- mutable borrow later used here
 
 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
-  --> $DIR/two-phase-activation-sharing-interference.rs:58:14
+  --> $DIR/two-phase-activation-sharing-interference.rs:56:14
    |
 LL |     let y = &mut x;
    |             ------ mutable borrow occurs here
diff --git a/tests/ui/borrowck/two-phase-activation-sharing-interference.rs b/tests/ui/borrowck/two-phase-activation-sharing-interference.rs
index beee991..1b4526a 100644
--- a/tests/ui/borrowck/two-phase-activation-sharing-interference.rs
+++ b/tests/ui/borrowck/two-phase-activation-sharing-interference.rs
@@ -1,6 +1,7 @@
 //@ revisions: nll_target
 
 // The following revisions are disabled due to missing support from two-phase beyond autorefs
+//@ unused-revision-names: nll_beyond
 //@[nll_beyond] compile-flags: -Z two-phase-beyond-autoref
 
 // This is an important corner case pointed out by Niko: one is
@@ -36,8 +37,7 @@
     let z = &x;
     //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
     *y += 1;
-    //[lxl_beyond]~^   ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
-    //[nll_beyond]~^^  ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
+    //[nll_beyond]~^   ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
     read(z);
 }
 
@@ -48,8 +48,6 @@
     //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
     read(z);
     *y += 1;
-    //[lxl_beyond]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
-    // (okay with (generalized) nll today)
 }
 
 fn should_also_eventually_be_ok_with_nll() {
@@ -58,8 +56,6 @@
     let _z = &x;
     //[nll_target]~^ ERROR cannot borrow `x` as immutable because it is also borrowed as mutable
     *y += 1;
-    //[lxl_beyond]~^ ERROR cannot borrow `x` as mutable because it is also borrowed as immutable
-    // (okay with (generalized) nll today)
 }
 
 fn main() { }
diff --git a/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr b/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr
index 1356c80..b7a1de0 100644
--- a/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr
+++ b/tests/ui/borrowck/two-phase-allow-access-during-reservation.nll_target.stderr
@@ -1,5 +1,5 @@
 error[E0503]: cannot use `i` because it was mutably borrowed
-  --> $DIR/two-phase-allow-access-during-reservation.rs:26:19
+  --> $DIR/two-phase-allow-access-during-reservation.rs:27:19
    |
 LL |     /*1*/ let p = &mut i; // (reservation of `i` starts here)
    |                   ------ `i` is borrowed here
@@ -11,7 +11,7 @@
    |           ------- borrow later used here
 
 error[E0503]: cannot use `i` because it was mutably borrowed
-  --> $DIR/two-phase-allow-access-during-reservation.rs:31:19
+  --> $DIR/two-phase-allow-access-during-reservation.rs:32:19
    |
 LL |     /*1*/ let p = &mut i; // (reservation of `i` starts here)
    |                   ------ `i` is borrowed here
diff --git a/tests/ui/borrowck/two-phase-allow-access-during-reservation.rs b/tests/ui/borrowck/two-phase-allow-access-during-reservation.rs
index e6b2501..6b5a2f5 100644
--- a/tests/ui/borrowck/two-phase-allow-access-during-reservation.rs
+++ b/tests/ui/borrowck/two-phase-allow-access-during-reservation.rs
@@ -1,6 +1,7 @@
 //@ revisions: nll_target
 
 // The following revisions are disabled due to missing support for two_phase_beyond_autoref
+//@ unused-revision-names: nll_beyond
 //@[nll_beyond] compile-flags: -Z two_phase_beyond_autoref
 
 // This is the second counter-example from Niko's blog post
diff --git a/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr b/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr
index e122977..c9d49b8 100644
--- a/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr
+++ b/tests/ui/borrowck/two-phase-nonrecv-autoref.base.stderr
@@ -1,5 +1,5 @@
 error[E0499]: cannot borrow `*f` as mutable more than once at a time
-  --> $DIR/two-phase-nonrecv-autoref.rs:50:11
+  --> $DIR/two-phase-nonrecv-autoref.rs:51:11
    |
 LL |         f(f(10));
    |         - ^ second mutable borrow occurs here
@@ -8,7 +8,7 @@
    |         first borrow later used by call
 
 error[E0382]: use of moved value: `f`
-  --> $DIR/two-phase-nonrecv-autoref.rs:57:11
+  --> $DIR/two-phase-nonrecv-autoref.rs:58:11
    |
 LL |     fn twice_ten_so<F: FnOnce(i32) -> i32>(f: Box<F>) {
    |                                            - move occurs because `f` has type `Box<F>`, which does not implement the `Copy` trait
@@ -18,7 +18,7 @@
    |         value moved here
 
 error[E0499]: cannot borrow `*f` as mutable more than once at a time
-  --> $DIR/two-phase-nonrecv-autoref.rs:62:11
+  --> $DIR/two-phase-nonrecv-autoref.rs:63:11
    |
 LL |         f(f(10));
    |         - ^ second mutable borrow occurs here
@@ -27,7 +27,7 @@
    |         first borrow later used by call
 
 error[E0382]: use of moved value: `f`
-  --> $DIR/two-phase-nonrecv-autoref.rs:69:11
+  --> $DIR/two-phase-nonrecv-autoref.rs:70:11
    |
 LL |     fn twice_ten_oo(f: Box<dyn FnOnce(i32) -> i32>) {
    |                     - move occurs because `f` has type `Box<dyn FnOnce(i32) -> i32>`, which does not implement the `Copy` trait
@@ -37,7 +37,7 @@
    |         value moved here
 
 error[E0502]: cannot borrow `a` as immutable because it is also borrowed as mutable
-  --> $DIR/two-phase-nonrecv-autoref.rs:107:27
+  --> $DIR/two-phase-nonrecv-autoref.rs:108:27
    |
 LL |     double_access(&mut a, &a);
    |     ------------- ------  ^^ immutable borrow occurs here
@@ -46,7 +46,7 @@
    |     mutable borrow later used by call
 
 error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable
-  --> $DIR/two-phase-nonrecv-autoref.rs:132:7
+  --> $DIR/two-phase-nonrecv-autoref.rs:133:7
    |
 LL |     i[i[3]] = 4;
    |     --^----
@@ -56,18 +56,18 @@
    |     mutable borrow occurs here
    |
 help: try adding a local storing this...
-  --> $DIR/two-phase-nonrecv-autoref.rs:132:8
+  --> $DIR/two-phase-nonrecv-autoref.rs:133:8
    |
 LL |     i[i[3]] = 4;
    |        ^^^
 help: ...and then using that local here
-  --> $DIR/two-phase-nonrecv-autoref.rs:132:6
+  --> $DIR/two-phase-nonrecv-autoref.rs:133:6
    |
 LL |     i[i[3]] = 4;
    |      ^^^^^^
 
 error[E0502]: cannot borrow `i` as immutable because it is also borrowed as mutable
-  --> $DIR/two-phase-nonrecv-autoref.rs:138:7
+  --> $DIR/two-phase-nonrecv-autoref.rs:139:7
    |
 LL |     i[i[3]] = i[4];
    |     --^----
@@ -77,12 +77,12 @@
    |     mutable borrow occurs here
    |
 help: try adding a local storing this...
-  --> $DIR/two-phase-nonrecv-autoref.rs:138:8
+  --> $DIR/two-phase-nonrecv-autoref.rs:139:8
    |
 LL |     i[i[3]] = i[4];
    |        ^^^
 help: ...and then using that local here
-  --> $DIR/two-phase-nonrecv-autoref.rs:138:6
+  --> $DIR/two-phase-nonrecv-autoref.rs:139:6
    |
 LL |     i[i[3]] = i[4];
    |      ^^^^^^
diff --git a/tests/ui/borrowck/two-phase-nonrecv-autoref.rs b/tests/ui/borrowck/two-phase-nonrecv-autoref.rs
index f52e9c2..3a8ab4e 100644
--- a/tests/ui/borrowck/two-phase-nonrecv-autoref.rs
+++ b/tests/ui/borrowck/two-phase-nonrecv-autoref.rs
@@ -1,5 +1,6 @@
 //@ revisions: base
 
+//@ unused-revision-names: g2p
 //@[g2p]compile-flags: -Z two-phase-beyond-autoref
 // the above revision is disabled until two-phase-beyond-autoref support is better
 
diff --git a/tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr b/tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr
index b1e4392..5eda482 100644
--- a/tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr
+++ b/tests/ui/borrowck/two-phase-reservation-sharing-interference.nll_target.stderr
@@ -1,5 +1,5 @@
 error[E0502]: cannot borrow `vec` as mutable because it is also borrowed as immutable
-  --> $DIR/two-phase-reservation-sharing-interference.rs:32:17
+  --> $DIR/two-phase-reservation-sharing-interference.rs:33:17
    |
 LL |         let shared = &vec;
    |                      ---- immutable borrow occurs here
diff --git a/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs b/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs
index b6bcf7b..6144657 100644
--- a/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs
+++ b/tests/ui/borrowck/two-phase-reservation-sharing-interference.rs
@@ -1,6 +1,7 @@
 //@ revisions: nll_target
 
 // The nll_beyond revision is disabled due to missing support from two-phase beyond autorefs
+//@ unused-revision-names: nll_beyond
 //@[nll_beyond]compile-flags: -Z two-phase-beyond-autoref
 //@[nll_beyond]should-fail
 
diff --git a/tests/ui/cast/ice-cast-type-with-error-124848.rs b/tests/ui/cast/ice-cast-type-with-error-124848.rs
new file mode 100644
index 0000000..9b3732b
--- /dev/null
+++ b/tests/ui/cast/ice-cast-type-with-error-124848.rs
@@ -0,0 +1,18 @@
+// Regression test for ICE #124848
+// Tests that there is no ICE when a cast
+// involves a type with error
+
+use std::cell::Cell;
+
+struct MyType<'a>(Cell<Option<&'unpinned mut MyType<'a>>>, Pin);
+//~^ ERROR use of undeclared lifetime name `'unpinned`
+//~| ERROR cannot find type `Pin` in this scope
+
+fn main() {
+    let mut unpinned = MyType(Cell::new(None));
+    //~^ ERROR his struct takes 2 arguments but 1 argument was supplied
+    let bad_addr = &unpinned as *const Cell<Option<&'a mut MyType<'a>>> as usize;
+    //~^ ERROR use of undeclared lifetime name `'a`
+    //~| ERROR use of undeclared lifetime name `'a`
+    //~| ERROR casting `&MyType<'_>` as `*const Cell<Option<&mut MyType<'_>>>` is invalid
+}
diff --git a/tests/ui/cast/ice-cast-type-with-error-124848.stderr b/tests/ui/cast/ice-cast-type-with-error-124848.stderr
new file mode 100644
index 0000000..2d86bf7
--- /dev/null
+++ b/tests/ui/cast/ice-cast-type-with-error-124848.stderr
@@ -0,0 +1,63 @@
+error[E0261]: use of undeclared lifetime name `'unpinned`
+  --> $DIR/ice-cast-type-with-error-124848.rs:7:32
+   |
+LL | struct MyType<'a>(Cell<Option<&'unpinned mut MyType<'a>>>, Pin);
+   |               -                ^^^^^^^^^ undeclared lifetime
+   |               |
+   |               help: consider introducing lifetime `'unpinned` here: `'unpinned,`
+
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/ice-cast-type-with-error-124848.rs:14:53
+   |
+LL | fn main() {
+   |        - help: consider introducing lifetime `'a` here: `<'a>`
+...
+LL |     let bad_addr = &unpinned as *const Cell<Option<&'a mut MyType<'a>>> as usize;
+   |                                                     ^^ undeclared lifetime
+
+error[E0261]: use of undeclared lifetime name `'a`
+  --> $DIR/ice-cast-type-with-error-124848.rs:14:67
+   |
+LL | fn main() {
+   |        - help: consider introducing lifetime `'a` here: `<'a>`
+...
+LL |     let bad_addr = &unpinned as *const Cell<Option<&'a mut MyType<'a>>> as usize;
+   |                                                                   ^^ undeclared lifetime
+
+error[E0412]: cannot find type `Pin` in this scope
+  --> $DIR/ice-cast-type-with-error-124848.rs:7:60
+   |
+LL | struct MyType<'a>(Cell<Option<&'unpinned mut MyType<'a>>>, Pin);
+   |                                                            ^^^ not found in this scope
+   |
+help: consider importing this struct
+   |
+LL + use std::pin::Pin;
+   |
+
+error[E0061]: this struct takes 2 arguments but 1 argument was supplied
+  --> $DIR/ice-cast-type-with-error-124848.rs:12:24
+   |
+LL |     let mut unpinned = MyType(Cell::new(None));
+   |                        ^^^^^^----------------- an argument is missing
+   |
+note: tuple struct defined here
+  --> $DIR/ice-cast-type-with-error-124848.rs:7:8
+   |
+LL | struct MyType<'a>(Cell<Option<&'unpinned mut MyType<'a>>>, Pin);
+   |        ^^^^^^
+help: provide the argument
+   |
+LL |     let mut unpinned = MyType(Cell::new(None), /* value */);
+   |                              ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+error[E0606]: casting `&MyType<'_>` as `*const Cell<Option<&mut MyType<'_>>>` is invalid
+  --> $DIR/ice-cast-type-with-error-124848.rs:14:20
+   |
+LL |     let bad_addr = &unpinned as *const Cell<Option<&'a mut MyType<'a>>> as usize;
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 6 previous errors
+
+Some errors have detailed explanations: E0061, E0261, E0412, E0606.
+For more information about an error, try `rustc --explain E0061`.
diff --git a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr b/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr
index 75df314..82b2d7d 100644
--- a/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr
+++ b/tests/ui/cfg/future-compat-crate-attributes-using-cfg_attr.stderr
@@ -1,4 +1,4 @@
-error: `crate_type` within an `#![cfg_attr] attribute is deprecated`
+error: `crate_type` within an `#![cfg_attr]` attribute is deprecated
   --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:4:18
    |
 LL | #![cfg_attr(foo, crate_type="bin")]
@@ -8,7 +8,7 @@
    = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632>
    = note: `#[deny(deprecated_cfg_attr_crate_type_name)]` on by default
 
-error: `crate_name` within an `#![cfg_attr] attribute is deprecated`
+error: `crate_name` within an `#![cfg_attr]` attribute is deprecated
   --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:9:18
    |
 LL | #![cfg_attr(foo, crate_name="bar")]
@@ -17,7 +17,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632>
 
-error: `crate_type` within an `#![cfg_attr] attribute is deprecated`
+error: `crate_type` within an `#![cfg_attr]` attribute is deprecated
   --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:4:18
    |
 LL | #![cfg_attr(foo, crate_type="bin")]
@@ -27,7 +27,7 @@
    = note: for more information, see issue #91632 <https://github.com/rust-lang/rust/issues/91632>
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: `crate_name` within an `#![cfg_attr] attribute is deprecated`
+error: `crate_name` within an `#![cfg_attr]` attribute is deprecated
   --> $DIR/future-compat-crate-attributes-using-cfg_attr.rs:9:18
    |
 LL | #![cfg_attr(foo, crate_name="bar")]
diff --git a/tests/ui/check-cfg/allow-same-level.stderr b/tests/ui/check-cfg/allow-same-level.stderr
index ae4c160..b311a80 100644
--- a/tests/ui/check-cfg/allow-same-level.stderr
+++ b/tests/ui/check-cfg/allow-same-level.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(FALSE)]
    |       ^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(FALSE)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/cargo-feature.none.stderr b/tests/ui/check-cfg/cargo-feature.none.stderr
index 627f03d..9d3117e 100644
--- a/tests/ui/check-cfg/cargo-feature.none.stderr
+++ b/tests/ui/check-cfg/cargo-feature.none.stderr
@@ -6,7 +6,7 @@
    |
    = note: no expected values for `feature`
    = help: consider adding `serde` as a feature in `Cargo.toml`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: (none)
@@ -17,7 +17,7 @@
    |
    = note: no expected values for `feature`
    = help: consider defining some features in `Cargo.toml`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition name: `tokio_unstable`
   --> $DIR/cargo-feature.rs:22:7
@@ -25,9 +25,13 @@
 LL | #[cfg(tokio_unstable)]
    |       ^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
-   = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(tokio_unstable)");` to the top of the `build.rs`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tokio_unstable)'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(tokio_unstable)");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition name: `CONFIG_NVME`
   --> $DIR/cargo-feature.rs:26:7
@@ -35,8 +39,12 @@
 LL | #[cfg(CONFIG_NVME = "m")]
    |       ^^^^^^^^^^^^^^^^^
    |
-   = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(CONFIG_NVME, values(\"m\"))");` to the top of the `build.rs`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(CONFIG_NVME, values("m"))'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(CONFIG_NVME, values(\"m\"))");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
 warning: 4 warnings emitted
 
diff --git a/tests/ui/check-cfg/cargo-feature.some.stderr b/tests/ui/check-cfg/cargo-feature.some.stderr
index 9cc5fb6..14e24cb 100644
--- a/tests/ui/check-cfg/cargo-feature.some.stderr
+++ b/tests/ui/check-cfg/cargo-feature.some.stderr
@@ -6,7 +6,7 @@
    |
    = note: expected values for `feature` are: `bitcode`
    = help: consider adding `serde` as a feature in `Cargo.toml`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition value: (none)
@@ -17,7 +17,7 @@
    |
    = note: expected values for `feature` are: `bitcode`
    = help: consider defining some features in `Cargo.toml`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition name: `tokio_unstable`
   --> $DIR/cargo-feature.rs:22:7
@@ -25,9 +25,13 @@
 LL | #[cfg(tokio_unstable)]
    |       ^^^^^^^^^^^^^^
    |
-   = help: expected names are: `CONFIG_NVME`, `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
-   = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(tokio_unstable)");` to the top of the `build.rs`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = help: expected names are: `CONFIG_NVME`, `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tokio_unstable)'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(tokio_unstable)");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `m`
   --> $DIR/cargo-feature.rs:26:7
@@ -38,8 +42,12 @@
    |                     help: there is a expected value with a similar name: `"y"`
    |
    = note: expected values for `CONFIG_NVME` are: `y`
-   = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(CONFIG_NVME, values(\"m\"))");` to the top of the `build.rs`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(CONFIG_NVME, values("m"))'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(CONFIG_NVME, values(\"m\"))");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
 warning: 4 warnings emitted
 
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr
index 4975129..08bd438 100644
--- a/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-duplicate.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(value)]
    |       ^^^^^
    |
-   = help: expected names are: `bar`, `bee`, `clippy`, `cow`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `bar`, `bee`, `clippy`, `cow`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(value)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr
index 6404556..6db1144 100644
--- a/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name-multiple.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(my_value)]
    |       ^^^^^^^^
    |
-   = help: expected names are: `bar`, `clippy`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `bar`, `clippy`, `debug_assertions`, `doc`, `doctest`, `foo`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(my_value)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr
index bda1a60..a5f8176 100644
--- a/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr
+++ b/tests/ui/check-cfg/cfg-value-for-cfg-name.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(linux)]
    |       ^^^^^ help: found config with similar value: `target_os = "linux"`
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(linux)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/compact-names.stderr b/tests/ui/check-cfg/compact-names.stderr
index 079be8d..6fecdb5 100644
--- a/tests/ui/check-cfg/compact-names.stderr
+++ b/tests/ui/check-cfg/compact-names.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(target(os = "linux", architecture = "arm"))]
    |                            ^^^^^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(target_architecture, values("arm"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/compact-values.stderr b/tests/ui/check-cfg/compact-values.stderr
index 4fe921d..c8d14f8 100644
--- a/tests/ui/check-cfg/compact-values.stderr
+++ b/tests/ui/check-cfg/compact-values.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(target(os = "linux", pointer_width = "X"))]
    |                            ^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_pointer_width` are: `16`, `32`, `64`
+   = note: expected values for `target_pointer_width` are: `16`, `32`, and `64`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
 
diff --git a/tests/ui/check-cfg/concat-values.stderr b/tests/ui/check-cfg/concat-values.stderr
index a508c39..ec74095 100644
--- a/tests/ui/check-cfg/concat-values.stderr
+++ b/tests/ui/check-cfg/concat-values.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(my_cfg)]
    |       ^^^^^^
    |
-   = note: expected values for `my_cfg` are: `bar`, `foo`
+   = note: expected values for `my_cfg` are: `bar` and `foo`
    = help: to expect this configuration use `--check-cfg=cfg(my_cfg)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
@@ -15,7 +15,7 @@
 LL | #[cfg(my_cfg = "unk")]
    |       ^^^^^^^^^^^^^^
    |
-   = note: expected values for `my_cfg` are: `bar`, `foo`
+   = note: expected values for `my_cfg` are: `bar` and `foo`
    = help: to expect this configuration use `--check-cfg=cfg(my_cfg, values("unk"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
diff --git a/tests/ui/check-cfg/diagnotics.cargo.stderr b/tests/ui/check-cfg/diagnotics.cargo.stderr
index 1b75056..a440cca 100644
--- a/tests/ui/check-cfg/diagnotics.cargo.stderr
+++ b/tests/ui/check-cfg/diagnotics.cargo.stderr
@@ -1,62 +1,70 @@
 warning: unexpected `cfg` condition name: `featur`
-  --> $DIR/diagnotics.rs:8:7
+  --> $DIR/diagnotics.rs:9:7
    |
 LL | #[cfg(featur)]
    |       ^^^^^^ help: there is a config with a similar name: `feature`
    |
    = help: expected values for `feature` are: `foo`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition name: `featur`
-  --> $DIR/diagnotics.rs:12:7
+  --> $DIR/diagnotics.rs:13:7
    |
 LL | #[cfg(featur = "foo")]
    |       ^^^^^^^^^^^^^^
    |
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 help: there is a config with a similar name and value
    |
 LL | #[cfg(feature = "foo")]
    |       ~~~~~~~
 
 warning: unexpected `cfg` condition name: `featur`
-  --> $DIR/diagnotics.rs:16:7
+  --> $DIR/diagnotics.rs:17:7
    |
 LL | #[cfg(featur = "fo")]
    |       ^^^^^^^^^^^^^
    |
    = help: expected values for `feature` are: `foo`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 help: there is a config with a similar name and different values
    |
 LL | #[cfg(feature = "foo")]
    |       ~~~~~~~~~~~~~~~
 
 warning: unexpected `cfg` condition name: `no_value`
-  --> $DIR/diagnotics.rs:23:7
+  --> $DIR/diagnotics.rs:24:7
    |
 LL | #[cfg(no_value)]
    |       ^^^^^^^^ help: there is a config with a similar name: `no_values`
    |
-   = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(no_value)");` to the top of the `build.rs`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(no_value)'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(no_value)");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition name: `no_value`
-  --> $DIR/diagnotics.rs:27:7
+  --> $DIR/diagnotics.rs:28:7
    |
 LL | #[cfg(no_value = "foo")]
    |       ^^^^^^^^^^^^^^^^
    |
-   = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(no_value, values(\"foo\"))");` to the top of the `build.rs`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(no_value, values("foo"))'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(no_value, values(\"foo\"))");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 help: there is a config with a similar name and no value
    |
 LL | #[cfg(no_values)]
    |       ~~~~~~~~~
 
 warning: unexpected `cfg` condition value: `bar`
-  --> $DIR/diagnotics.rs:31:7
+  --> $DIR/diagnotics.rs:32:7
    |
 LL | #[cfg(no_values = "bar")]
    |       ^^^^^^^^^--------
@@ -64,8 +72,28 @@
    |                help: remove the value
    |
    = note: no expected value for `no_values`
-   = help: consider using a Cargo feature instead or adding `println!("cargo::rustc-check-cfg=cfg(no_values, values(\"bar\"))");` to the top of the `build.rs`
-   = note: see <https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-check-cfg> for more information about checking conditional configuration
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(no_values, values("bar"))'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(no_values, values(\"bar\"))");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
 
-warning: 6 warnings emitted
+warning: unexpected `cfg` condition value: `quote"`
+  --> $DIR/diagnotics.rs:36:7
+   |
+LL | #[cfg(quote = "quote\"")]
+   |       ^^^^^^^^---------
+   |               |
+   |               help: there is a expected value with a similar name: `"quote"`
+   |
+   = note: expected values for `quote` are: `quote`
+   = help: consider using a Cargo feature instead
+   = help: or consider adding in `Cargo.toml` the `check-cfg` lint config for the lint:
+            [lints.rust]
+            unexpected_cfgs = { level = "warn", check-cfg = ['cfg(quote, values("quote\""))'] }
+   = help: or consider adding `println!("cargo::rustc-check-cfg=cfg(quote, values(\"quote\\\"\"))");` to the top of the `build.rs`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg/cargo-specifics.html> for more information about checking conditional configuration
+
+warning: 7 warnings emitted
 
diff --git a/tests/ui/check-cfg/diagnotics.rs b/tests/ui/check-cfg/diagnotics.rs
index b8268ec..7155d7c 100644
--- a/tests/ui/check-cfg/diagnotics.rs
+++ b/tests/ui/check-cfg/diagnotics.rs
@@ -4,6 +4,7 @@
 //@ [rustc]unset-rustc-env:CARGO_CRATE_NAME
 //@ [cargo]rustc-env:CARGO_CRATE_NAME=foo
 //@ compile-flags: --check-cfg=cfg(feature,values("foo")) --check-cfg=cfg(no_values)
+//@ compile-flags: --check-cfg=cfg(quote,values("quote"))
 
 #[cfg(featur)]
 //~^ WARNING unexpected `cfg` condition name
@@ -32,4 +33,8 @@
 //~^ WARNING unexpected `cfg` condition value
 fn no_values() {}
 
+#[cfg(quote = "quote\"")]
+//~^ WARNING unexpected `cfg` condition value
+fn no_values() {}
+
 fn main() {}
diff --git a/tests/ui/check-cfg/diagnotics.rustc.stderr b/tests/ui/check-cfg/diagnotics.rustc.stderr
index 0bd6ce1..6868be4 100644
--- a/tests/ui/check-cfg/diagnotics.rustc.stderr
+++ b/tests/ui/check-cfg/diagnotics.rustc.stderr
@@ -1,5 +1,5 @@
 warning: unexpected `cfg` condition name: `featur`
-  --> $DIR/diagnotics.rs:8:7
+  --> $DIR/diagnotics.rs:9:7
    |
 LL | #[cfg(featur)]
    |       ^^^^^^ help: there is a config with a similar name: `feature`
@@ -10,7 +10,7 @@
    = note: `#[warn(unexpected_cfgs)]` on by default
 
 warning: unexpected `cfg` condition name: `featur`
-  --> $DIR/diagnotics.rs:12:7
+  --> $DIR/diagnotics.rs:13:7
    |
 LL | #[cfg(featur = "foo")]
    |       ^^^^^^^^^^^^^^
@@ -23,7 +23,7 @@
    |       ~~~~~~~
 
 warning: unexpected `cfg` condition name: `featur`
-  --> $DIR/diagnotics.rs:16:7
+  --> $DIR/diagnotics.rs:17:7
    |
 LL | #[cfg(featur = "fo")]
    |       ^^^^^^^^^^^^^
@@ -37,7 +37,7 @@
    |       ~~~~~~~~~~~~~~~
 
 warning: unexpected `cfg` condition name: `no_value`
-  --> $DIR/diagnotics.rs:23:7
+  --> $DIR/diagnotics.rs:24:7
    |
 LL | #[cfg(no_value)]
    |       ^^^^^^^^ help: there is a config with a similar name: `no_values`
@@ -46,7 +46,7 @@
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition name: `no_value`
-  --> $DIR/diagnotics.rs:27:7
+  --> $DIR/diagnotics.rs:28:7
    |
 LL | #[cfg(no_value = "foo")]
    |       ^^^^^^^^^^^^^^^^
@@ -59,7 +59,7 @@
    |       ~~~~~~~~~
 
 warning: unexpected `cfg` condition value: `bar`
-  --> $DIR/diagnotics.rs:31:7
+  --> $DIR/diagnotics.rs:32:7
    |
 LL | #[cfg(no_values = "bar")]
    |       ^^^^^^^^^--------
@@ -70,5 +70,17 @@
    = help: to expect this configuration use `--check-cfg=cfg(no_values, values("bar"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
-warning: 6 warnings emitted
+warning: unexpected `cfg` condition value: `quote"`
+  --> $DIR/diagnotics.rs:36:7
+   |
+LL | #[cfg(quote = "quote\"")]
+   |       ^^^^^^^^---------
+   |               |
+   |               help: there is a expected value with a similar name: `"quote"`
+   |
+   = note: expected values for `quote` are: `quote`
+   = help: to expect this configuration use `--check-cfg=cfg(quote, values("quote\""))`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
+
+warning: 7 warnings emitted
 
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 c196f60..2497864 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
+++ b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
@@ -30,7 +30,7 @@
    = 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`
-  --> $DIR/exhaustive-names-values.rs:25:7
+  --> $DIR/exhaustive-names-values.rs:24:7
    |
 LL | #[cfg(feature = "std")]
    |       ^^^^^^^^^^^^^^^
diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
index 6344739..a7d4c6d 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
+++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr
index 6344739..a7d4c6d 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.full.stderr
+++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/exhaustive-names-values.rs b/tests/ui/check-cfg/exhaustive-names-values.rs
index a6190f1..7b2d89b 100644
--- a/tests/ui/check-cfg/exhaustive-names-values.rs
+++ b/tests/ui/check-cfg/exhaustive-names-values.rs
@@ -16,15 +16,13 @@
 pub fn f() {}
 
 #[cfg(feature = "unk")]
-//[empty_names_values]~^ WARNING unexpected `cfg` condition name
-//[empty_cfg]~^^ WARNING unexpected `cfg` condition name
-//[feature]~^^^ WARNING unexpected `cfg` condition value
-//[full]~^^^^ WARNING unexpected `cfg` condition value
+//[empty_cfg]~^ WARNING unexpected `cfg` condition name
+//[feature]~^^ WARNING unexpected `cfg` condition value
+//[full]~^^^ WARNING unexpected `cfg` condition value
 pub fn feat() {}
 
 #[cfg(feature = "std")]
-//[empty_names_values]~^ WARNING unexpected `cfg` condition name
-//[empty_cfg]~^^ WARNING unexpected `cfg` condition name
+//[empty_cfg]~^ WARNING unexpected `cfg` condition name
 pub fn feat() {}
 
 #[cfg(windows)]
diff --git a/tests/ui/check-cfg/exhaustive-names.stderr b/tests/ui/check-cfg/exhaustive-names.stderr
index 605825c..7ac3241 100644
--- a/tests/ui/check-cfg/exhaustive-names.stderr
+++ b/tests/ui/check-cfg/exhaustive-names.stderr
@@ -4,7 +4,7 @@
 LL | #[cfg(unknown_key = "value")]
    |       ^^^^^^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(unknown_key, values("value"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr
index 5459169..8c1bf5a 100644
--- a/tests/ui/check-cfg/mix.stderr
+++ b/tests/ui/check-cfg/mix.stderr
@@ -44,7 +44,7 @@
 LL | #[cfg_attr(uu, test)]
    |            ^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(uu)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
@@ -251,7 +251,7 @@
 LL |     cfg!(target_feature = "zebra");
    |          ^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2` and 188 more
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, and `bmi2` and 188 more
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: 27 warnings emitted
diff --git a/tests/ui/check-cfg/stmt-no-ice.stderr b/tests/ui/check-cfg/stmt-no-ice.stderr
index ab0deae..e8b61d8 100644
--- a/tests/ui/check-cfg/stmt-no-ice.stderr
+++ b/tests/ui/check-cfg/stmt-no-ice.stderr
@@ -4,7 +4,7 @@
 LL |     #[cfg(crossbeam_loom)]
    |           ^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(crossbeam_loom)`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
diff --git a/tests/ui/check-cfg/unexpected-cfg-value.stderr b/tests/ui/check-cfg/unexpected-cfg-value.stderr
index efcf65b..0fa0dde 100644
--- a/tests/ui/check-cfg/unexpected-cfg-value.stderr
+++ b/tests/ui/check-cfg/unexpected-cfg-value.stderr
@@ -6,7 +6,7 @@
    |                 |
    |                 help: there is a expected value with a similar name: `"serde"`
    |
-   = note: expected values for `feature` are: `full`, `serde`
+   = note: expected values for `feature` are: `full` and `serde`
    = help: to expect this configuration use `--check-cfg=cfg(feature, values("sedre"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
    = note: `#[warn(unexpected_cfgs)]` on by default
@@ -17,7 +17,7 @@
 LL | #[cfg(feature = "rand")]
    |       ^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `feature` are: `full`, `serde`
+   = note: expected values for `feature` are: `full` and `serde`
    = help: to expect this configuration use `--check-cfg=cfg(feature, values("rand"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
diff --git a/tests/ui/check-cfg/values-none.concat_1.stderr b/tests/ui/check-cfg/values-none.concat_1.stderr
new file mode 100644
index 0000000..b8f0b02
--- /dev/null
+++ b/tests/ui/check-cfg/values-none.concat_1.stderr
@@ -0,0 +1,13 @@
+warning: unexpected `cfg` condition value: `bar`
+  --> $DIR/values-none.rs:16:7
+   |
+LL | #[cfg(foo = "bar")]
+   |       ^^^^^^^^^^^
+   |
+   = note: expected values for `foo` are: (none), `too`
+   = help: to expect this configuration use `--check-cfg=cfg(foo, values("bar"))`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/values-none.concat_2.stderr b/tests/ui/check-cfg/values-none.concat_2.stderr
new file mode 100644
index 0000000..b8f0b02
--- /dev/null
+++ b/tests/ui/check-cfg/values-none.concat_2.stderr
@@ -0,0 +1,13 @@
+warning: unexpected `cfg` condition value: `bar`
+  --> $DIR/values-none.rs:16:7
+   |
+LL | #[cfg(foo = "bar")]
+   |       ^^^^^^^^^^^
+   |
+   = note: expected values for `foo` are: (none), `too`
+   = help: to expect this configuration use `--check-cfg=cfg(foo, values("bar"))`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/values-none.rs b/tests/ui/check-cfg/values-none.rs
index 6856d2f..447fde2 100644
--- a/tests/ui/check-cfg/values-none.rs
+++ b/tests/ui/check-cfg/values-none.rs
@@ -1,7 +1,7 @@
 //@ check-pass
 //
 //@ no-auto-check-cfg
-//@ revisions: explicit implicit
+//@ revisions: explicit implicit simple concat_1 concat_2
 //@ [explicit]compile-flags: --check-cfg=cfg(foo,values(none()))
 //@ [implicit]compile-flags: --check-cfg=cfg(foo)
 //@ [simple]  compile-flags: --check-cfg=cfg(foo,values(none(),"too"))
diff --git a/tests/ui/check-cfg/values-none.simple.stderr b/tests/ui/check-cfg/values-none.simple.stderr
new file mode 100644
index 0000000..b8f0b02
--- /dev/null
+++ b/tests/ui/check-cfg/values-none.simple.stderr
@@ -0,0 +1,13 @@
+warning: unexpected `cfg` condition value: `bar`
+  --> $DIR/values-none.rs:16:7
+   |
+LL | #[cfg(foo = "bar")]
+   |       ^^^^^^^^^^^
+   |
+   = note: expected values for `foo` are: (none), `too`
+   = help: to expect this configuration use `--check-cfg=cfg(foo, values("bar"))`
+   = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
+   = note: `#[warn(unexpected_cfgs)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/check-cfg/well-known-names.stderr b/tests/ui/check-cfg/well-known-names.stderr
index 2ce6fe8..4113021 100644
--- a/tests/ui/check-cfg/well-known-names.stderr
+++ b/tests/ui/check-cfg/well-known-names.stderr
@@ -18,7 +18,7 @@
 LL | #[cfg(features = "foo")]
    |       ^^^^^^^^^^^^^^^^
    |
-   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, `windows`
+   = help: expected names are: `clippy`, `debug_assertions`, `doc`, `doctest`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `rustfmt`, `sanitize`, `sanitizer_cfi_generalize_pointers`, `sanitizer_cfi_normalize_integers`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `ub_checks`, `unix`, and `windows`
    = help: to expect this configuration use `--check-cfg=cfg(features, values("foo"))`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr
index db4a5fd..c13446b 100644
--- a/tests/ui/check-cfg/well-known-values.stderr
+++ b/tests/ui/check-cfg/well-known-values.stderr
@@ -71,7 +71,7 @@
 LL |     panic = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `panic` are: `abort`, `unwind`
+   = note: expected values for `panic` are: `abort` and `unwind`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -91,7 +91,7 @@
 LL |     relocation_model = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `relocation_model` are: `dynamic-no-pic`, `pic`, `pie`, `ropi`, `ropi-rwpi`, `rwpi`, `static`
+   = note: expected values for `relocation_model` are: `dynamic-no-pic`, `pic`, `pie`, `ropi`, `ropi-rwpi`, `rwpi`, and `static`
    = 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`
@@ -111,7 +111,7 @@
 LL |     sanitize = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, `thread`
+   = note: expected values for `sanitize` are: `address`, `cfi`, `dataflow`, `hwaddress`, `kcfi`, `kernel-address`, `leak`, `memory`, `memtag`, `safestack`, `shadow-call-stack`, and `thread`
    = 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`
@@ -120,7 +120,7 @@
 LL |     target_abi = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elf`, `fortanix`, `ilp32`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, `x32`
+   = note: expected values for `target_abi` are: ``, `abi64`, `abiv2`, `abiv2hf`, `eabi`, `eabihf`, `elf`, `fortanix`, `ilp32`, `llvm`, `macabi`, `sim`, `softfloat`, `spe`, `uwp`, `vec-extabi`, and `x32`
    = note: 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`
@@ -129,7 +129,7 @@
 LL |     target_arch = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_arch` are: `aarch64`, `arm`, `arm64ec`, `avr`, `bpf`, `csky`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips32r6`, `mips64`, `mips64r6`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, `x86_64`
+   = note: expected values for `target_arch` are: `aarch64`, `arm`, `arm64ec`, `avr`, `bpf`, `csky`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips32r6`, `mips64`, `mips64r6`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, and `x86_64`
    = 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`
@@ -138,7 +138,7 @@
 LL |     target_endian = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_endian` are: `big`, `little`
+   = note: expected values for `target_endian` are: `big` and `little`
    = 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`
@@ -147,7 +147,7 @@
 LL |     target_env = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `p2`, `psx`, `relibc`, `sgx`, `uclibc`
+   = note: expected values for `target_env` are: ``, `gnu`, `msvc`, `musl`, `newlib`, `nto70`, `nto71`, `ohos`, `p2`, `psx`, `relibc`, `sgx`, and `uclibc`
    = 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`
@@ -156,7 +156,7 @@
 LL |     target_family = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_family` are: `unix`, `wasm`, `windows`
+   = note: expected values for `target_family` are: `unix`, `wasm`, and `windows`
    = 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`
@@ -165,7 +165,7 @@
 LL |     target_feature = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, `zkt`
+   = note: expected values for `target_feature` are: `10e60`, `2e3`, `3e3r1`, `3e3r2`, `3e3r3`, `3e7`, `7e10`, `a`, `aclass`, `adx`, `aes`, `altivec`, `alu32`, `atomics`, `avx`, `avx2`, `avx512bf16`, `avx512bitalg`, `avx512bw`, `avx512cd`, `avx512dq`, `avx512er`, `avx512f`, `avx512fp16`, `avx512ifma`, `avx512pf`, `avx512vbmi`, `avx512vbmi2`, `avx512vl`, `avx512vnni`, `avx512vp2intersect`, `avx512vpopcntdq`, `bf16`, `bmi1`, `bmi2`, `bti`, `bulk-memory`, `c`, `cache`, `cmpxchg16b`, `crc`, `crt-static`, `d`, `d32`, `dit`, `doloop`, `dotprod`, `dpb`, `dpb2`, `dsp`, `dsp1e2`, `dspe60`, `e`, `e1`, `e2`, `edsp`, `elrw`, `ermsb`, `exception-handling`, `extended-const`, `f`, `f16c`, `f32mm`, `f64mm`, `fcma`, `fdivdu`, `fhm`, `flagm`, `float1e2`, `float1e3`, `float3e4`, `float7e60`, `floate1`, `fma`, `fp-armv8`, `fp16`, `fp64`, `fpuv2_df`, `fpuv2_sf`, `fpuv3_df`, `fpuv3_hf`, `fpuv3_hi`, `fpuv3_sf`, `frecipe`, `frintts`, `fxsr`, `gfni`, `hard-float`, `hard-float-abi`, `hard-tp`, `high-registers`, `hvx`, `hvx-length128b`, `hwdiv`, `i8mm`, `jsconv`, `lahfsahf`, `lasx`, `lbt`, `lor`, `lse`, `lsx`, `lvz`, `lzcnt`, `m`, `mclass`, `movbe`, `mp`, `mp1e2`, `msa`, `mte`, `multivalue`, `mutable-globals`, `neon`, `nontrapping-fptoint`, `nvic`, `paca`, `pacg`, `pan`, `pclmulqdq`, `pmuv3`, `popcnt`, `power10-vector`, `power8-altivec`, `power8-vector`, `power9-altivec`, `power9-vector`, `prfchw`, `rand`, `ras`, `rclass`, `rcpc`, `rcpc2`, `rdm`, `rdrand`, `rdseed`, `reference-types`, `relax`, `relaxed-simd`, `rtm`, `sb`, `sha`, `sha2`, `sha3`, `sign-ext`, `simd128`, `sm4`, `spe`, `ssbs`, `sse`, `sse2`, `sse3`, `sse4.1`, `sse4.2`, `sse4a`, `ssse3`, `sve`, `sve2`, `sve2-aes`, `sve2-bitperm`, `sve2-sha3`, `sve2-sm4`, `tbm`, `thumb-mode`, `thumb2`, `tme`, `trust`, `trustzone`, `ual`, `unaligned-scalar-mem`, `v`, `v5te`, `v6`, `v6k`, `v6t2`, `v7`, `v8`, `v8.1a`, `v8.2a`, `v8.3a`, `v8.4a`, `v8.5a`, `v8.6a`, `v8.7a`, `vaes`, `vdsp2e60f`, `vdspv1`, `vdspv2`, `vfp2`, `vfp3`, `vfp4`, `vh`, `virt`, `virtualization`, `vpclmulqdq`, `vsx`, `xsave`, `xsavec`, `xsaveopt`, `xsaves`, `zba`, `zbb`, `zbc`, `zbkb`, `zbkc`, `zbkx`, `zbs`, `zdinx`, `zfh`, `zfhmin`, `zfinx`, `zhinx`, `zhinxmin`, `zk`, `zkn`, `zknd`, `zkne`, `zknh`, `zkr`, `zks`, `zksed`, `zksh`, and `zkt`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -174,7 +174,7 @@
 LL |     target_has_atomic = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_has_atomic` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr`
+   = note: expected values for `target_has_atomic` are: (none), `128`, `16`, `32`, `64`, `8`, and `ptr`
    = 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`
@@ -183,7 +183,7 @@
 LL |     target_has_atomic_equal_alignment = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_has_atomic_equal_alignment` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr`
+   = note: expected values for `target_has_atomic_equal_alignment` are: (none), `128`, `16`, `32`, `64`, `8`, and `ptr`
    = 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`
@@ -192,7 +192,7 @@
 LL |     target_has_atomic_load_store = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_has_atomic_load_store` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr`
+   = note: expected values for `target_has_atomic_load_store` are: (none), `128`, `16`, `32`, `64`, `8`, and `ptr`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -201,7 +201,7 @@
 LL |     target_os = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, `zkvm`
+   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE`
@@ -210,7 +210,7 @@
 LL |     target_pointer_width = "_UNEXPECTED_VALUE",
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
-   = note: expected values for `target_pointer_width` are: `16`, `32`, `64`
+   = note: expected values for `target_pointer_width` are: `16`, `32`, and `64`
    = 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`
@@ -230,7 +230,7 @@
 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`, `wrs`
+   = 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: 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`
@@ -285,7 +285,7 @@
    |                   |
    |                   help: there is a expected value with a similar name: `"linux"`
    |
-   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, `zkvm`
+   = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm`
    = note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
 
 warning: 29 warnings emitted
diff --git a/tests/ui/closures/closure-return-type-mismatch.stderr b/tests/ui/closures/closure-return-type-mismatch.stderr
index 3a89d30..3a2f098 100644
--- a/tests/ui/closures/closure-return-type-mismatch.stderr
+++ b/tests/ui/closures/closure-return-type-mismatch.stderr
@@ -13,6 +13,9 @@
 error[E0308]: mismatched types
   --> $DIR/closure-return-type-mismatch.rs:12:20
    |
+LL |     || -> bool {
+   |           ---- expected `bool` because of return type
+LL |         if false {
 LL |             return "hello"
    |                    ^^^^^^^ expected `bool`, found `&str`
 
diff --git a/tests/ui/coercion/pin-dyn-dispatch-sound.rs b/tests/ui/coercion/pin-dyn-dispatch-sound.rs
new file mode 100644
index 0000000..b9d43eb
--- /dev/null
+++ b/tests/ui/coercion/pin-dyn-dispatch-sound.rs
@@ -0,0 +1,19 @@
+use std::marker::PhantomPinned;
+use std::pin::Pin;
+
+trait MyUnpinTrait {
+    fn into_pinned_type(self: Pin<&mut Self>) -> Pin<&mut PhantomPinned>;
+}
+impl MyUnpinTrait for PhantomPinned {
+    fn into_pinned_type(self: Pin<&mut Self>) -> Pin<&mut PhantomPinned> {
+        self
+    }
+}
+impl Unpin for dyn MyUnpinTrait {} //~ ERROR E0321
+
+// It would be unsound for this function to compile.
+fn pin_it(not_yet_pinned: &mut PhantomPinned) -> Pin<&mut PhantomPinned> {
+    Pin::new(not_yet_pinned as &mut dyn MyUnpinTrait).into_pinned_type()
+}
+
+fn main() {}
diff --git a/tests/ui/coercion/pin-dyn-dispatch-sound.stderr b/tests/ui/coercion/pin-dyn-dispatch-sound.stderr
new file mode 100644
index 0000000..45860bf
--- /dev/null
+++ b/tests/ui/coercion/pin-dyn-dispatch-sound.stderr
@@ -0,0 +1,9 @@
+error[E0321]: cross-crate traits with a default impl, like `Unpin`, can only be implemented for a struct/enum type, not `(dyn MyUnpinTrait + 'static)`
+  --> $DIR/pin-dyn-dispatch-sound.rs:12:1
+   |
+LL | impl Unpin for dyn MyUnpinTrait {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0321`.
diff --git a/tests/ui/coherence/associated-type2.rs b/tests/ui/coherence/associated-type2.rs
index 2aadfb0..68e98b6 100644
--- a/tests/ui/coherence/associated-type2.rs
+++ b/tests/ui/coherence/associated-type2.rs
@@ -1,6 +1,6 @@
 //! A regression test for #120343. The overlap error was previously
 //! silenced in coherence because projecting `<() as ToUnit>::Unit`
-//! failed. Then then silenced the missing items error in the `ToUnit`
+//! failed. Then silenced the missing items error in the `ToUnit`
 //! impl, causing us to not emit any errors and ICEing due to a
 //! `span_delay_bug`.
 
diff --git a/tests/ui/auxiliary/orphan-check-diagnostics.rs b/tests/ui/coherence/auxiliary/orphan-check-diagnostics.rs
similarity index 100%
rename from tests/ui/auxiliary/orphan-check-diagnostics.rs
rename to tests/ui/coherence/auxiliary/orphan-check-diagnostics.rs
diff --git a/tests/ui/orphan-check-diagnostics.rs b/tests/ui/coherence/orphan-check-diagnostics.rs
similarity index 100%
rename from tests/ui/orphan-check-diagnostics.rs
rename to tests/ui/coherence/orphan-check-diagnostics.rs
diff --git a/tests/ui/orphan-check-diagnostics.stderr b/tests/ui/coherence/orphan-check-diagnostics.stderr
similarity index 100%
rename from tests/ui/orphan-check-diagnostics.stderr
rename to tests/ui/coherence/orphan-check-diagnostics.stderr
diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
index 408eaff..d885281 100644
--- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
+++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.rs
@@ -28,8 +28,8 @@
 macro_rules! generate_s10 {
     ($expr: expr) => {
         #[cfg(feature = $expr)]
-        //~^ ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")`
-        //~| ERROR expected unsuffixed literal or identifier, found `concat!("nonexistent")`
+        //~^ ERROR expected unsuffixed literal, found `concat!("nonexistent")`
+        //~| ERROR expected unsuffixed literal, found `concat!("nonexistent")`
         struct S10;
     }
 }
diff --git a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
index 12557ff..3dd0823 100644
--- a/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
+++ b/tests/ui/conditional-compilation/cfg-attr-syntax-validation.stderr
@@ -54,7 +54,7 @@
    |           |
    |           help: consider removing the prefix
 
-error: expected unsuffixed literal or identifier, found `concat!("nonexistent")`
+error: expected unsuffixed literal, found `concat!("nonexistent")`
   --> $DIR/cfg-attr-syntax-validation.rs:30:25
    |
 LL |         #[cfg(feature = $expr)]
@@ -65,7 +65,7 @@
    |
    = note: this error originates in the macro `generate_s10` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: expected unsuffixed literal or identifier, found `concat!("nonexistent")`
+error: expected unsuffixed literal, found `concat!("nonexistent")`
   --> $DIR/cfg-attr-syntax-validation.rs:30:25
    |
 LL |         #[cfg(feature = $expr)]
diff --git a/tests/ui/const-generics/lookup-method.rs b/tests/ui/const-generics/lookup-method.rs
new file mode 100644
index 0000000..915935c
--- /dev/null
+++ b/tests/ui/const-generics/lookup-method.rs
@@ -0,0 +1,19 @@
+// https://github.com/rust-lang/rust/issues/124946
+
+struct Builder<const A: bool, const B: bool>;
+
+impl<const A: bool> Builder<A, false> {
+    fn cast(self) -> Builder<A, true> {
+        Builder
+    }
+}
+
+impl Builder<true, true> {
+    fn build(self) {}
+}
+
+fn main() {
+    let b = Builder::<false, false>;
+    b.cast().build();
+    //~^ ERROR: no method named `build` found for struct `Builder<false, true>` in the current scope
+}
diff --git a/tests/ui/const-generics/lookup-method.stderr b/tests/ui/const-generics/lookup-method.stderr
new file mode 100644
index 0000000..4cbd1e1
--- /dev/null
+++ b/tests/ui/const-generics/lookup-method.stderr
@@ -0,0 +1,15 @@
+error[E0599]: no method named `build` found for struct `Builder<false, true>` in the current scope
+  --> $DIR/lookup-method.rs:17:14
+   |
+LL | struct Builder<const A: bool, const B: bool>;
+   | -------------------------------------------- method `build` not found for this struct
+...
+LL |     b.cast().build();
+   |              ^^^^^ method not found in `Builder<false, true>`
+   |
+   = note: the method was found for
+           - `Builder<true, true>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/const-ptr/forbidden_slices.rs b/tests/ui/const-ptr/forbidden_slices.rs
index 85baeed..2550a3a 100644
--- a/tests/ui/const-ptr/forbidden_slices.rs
+++ b/tests/ui/const-ptr/forbidden_slices.rs
@@ -12,7 +12,7 @@
     slice::{from_ptr_range, from_raw_parts},
 };
 
-// Null is never valid for reads
+// Null is never valid for references
 pub static S0: &[u32] = unsafe { from_raw_parts(ptr::null(), 0) };
 //~^ ERROR: it is undefined behavior to use this value
 pub static S1: &[()] = unsafe { from_raw_parts(ptr::null(), 0) };
@@ -46,10 +46,11 @@
 };
 
 pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
-pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+//~^ ERROR it is undefined behavior to use this value
+pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; // errors inside libcore
 pub static R2: &[u32] = unsafe {
     let ptr = &D0 as *const u32;
-    from_ptr_range(ptr..ptr.add(2))
+    from_ptr_range(ptr..ptr.add(2)) // errors inside libcore
 };
 pub static R4: &[u8] = unsafe {
     //~^ ERROR: it is undefined behavior to use this value
diff --git a/tests/ui/const-ptr/forbidden_slices.stderr b/tests/ui/const-ptr/forbidden_slices.stderr
index 250366d..eb41a25 100644
--- a/tests/ui/const-ptr/forbidden_slices.stderr
+++ b/tests/ui/const-ptr/forbidden_slices.stderr
@@ -88,20 +88,16 @@
                HEX_DUMP
            }
 
-error[E0080]: could not evaluate static initializer
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
-   = note: out-of-bounds `offset_from`: null pointer is a dangling pointer (it has no provenance)
-   |
-note: inside `std::ptr::const_ptr::<impl *const u32>::sub_ptr`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `from_ptr_range::<'_, u32>`
-  --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
-note: inside `R0`
-  --> $DIR/forbidden_slices.rs:48:34
+error[E0080]: it is undefined behavior to use this value
+  --> $DIR/forbidden_slices.rs:48:1
    |
 LL | pub static R0: &[u32] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
-   |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference
+   |
+   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
+   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
+               HEX_DUMP
+           }
 
 error[E0080]: could not evaluate static initializer
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -113,9 +109,9 @@
 note: inside `from_ptr_range::<'_, ()>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
 note: inside `R1`
-  --> $DIR/forbidden_slices.rs:49:33
+  --> $DIR/forbidden_slices.rs:50:33
    |
-LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) };
+LL | pub static R1: &[()] = unsafe { from_ptr_range(ptr::null()..ptr::null()) }; // errors inside libcore
    |                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -127,13 +123,13 @@
 note: inside `std::ptr::const_ptr::<impl *const u32>::add`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `R2`
-  --> $DIR/forbidden_slices.rs:52:25
+  --> $DIR/forbidden_slices.rs:53:25
    |
-LL |     from_ptr_range(ptr..ptr.add(2))
+LL |     from_ptr_range(ptr..ptr.add(2)) // errors inside libcore
    |                         ^^^^^^^^^^
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:54:1
+  --> $DIR/forbidden_slices.rs:55:1
    |
 LL | pub static R4: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered uninitialized memory, but expected an integer
@@ -144,7 +140,7 @@
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:59:1
+  --> $DIR/forbidden_slices.rs:60:1
    |
 LL | pub static R5: &[u8] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered a pointer, but expected an integer
@@ -157,7 +153,7 @@
    = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:64:1
+  --> $DIR/forbidden_slices.rs:65:1
    |
 LL | pub static R6: &[bool] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .<deref>[0]: encountered 0x11, but expected a boolean
@@ -168,7 +164,7 @@
            }
 
 error[E0080]: it is undefined behavior to use this value
-  --> $DIR/forbidden_slices.rs:69:1
+  --> $DIR/forbidden_slices.rs:70:1
    |
 LL | pub static R7: &[u16] = unsafe {
    | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1)
@@ -186,7 +182,7 @@
 note: inside `std::ptr::const_ptr::<impl *const u64>::add`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `R8`
-  --> $DIR/forbidden_slices.rs:76:25
+  --> $DIR/forbidden_slices.rs:77:25
    |
 LL |     from_ptr_range(ptr..ptr.add(1))
    |                         ^^^^^^^^^^
@@ -201,7 +197,7 @@
 note: inside `from_ptr_range::<'_, u32>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
 note: inside `R9`
-  --> $DIR/forbidden_slices.rs:81:34
+  --> $DIR/forbidden_slices.rs:82:34
    |
 LL | pub static R9: &[u32] = unsafe { from_ptr_range(&D0..(&D0 as *const u32).add(1)) };
    |                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -216,7 +212,7 @@
 note: inside `from_ptr_range::<'_, u32>`
   --> $SRC_DIR/core/src/slice/raw.rs:LL:COL
 note: inside `R10`
-  --> $DIR/forbidden_slices.rs:82:35
+  --> $DIR/forbidden_slices.rs:83:35
    |
 LL | pub static R10: &[u32] = unsafe { from_ptr_range(&D0..&D0) };
    |                                   ^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/consts/const-compare-bytes-ub.rs b/tests/ui/consts/const-compare-bytes-ub.rs
index b357bab..903ba15 100644
--- a/tests/ui/consts/const-compare-bytes-ub.rs
+++ b/tests/ui/consts/const-compare-bytes-ub.rs
@@ -7,11 +7,11 @@
 
 fn main() {
     const LHS_NULL: i32 = unsafe {
-        compare_bytes(0 as *const u8, 2 as *const u8, 0)
+        compare_bytes(0 as *const u8, 2 as *const u8, 1)
         //~^ ERROR evaluation of constant value failed
     };
     const RHS_NULL: i32 = unsafe {
-        compare_bytes(1 as *const u8, 0 as *const u8, 0)
+        compare_bytes(1 as *const u8, 0 as *const u8, 1)
         //~^ ERROR evaluation of constant value failed
     };
     const DANGLING_PTR_NON_ZERO_LENGTH: i32 = unsafe {
diff --git a/tests/ui/consts/const-compare-bytes-ub.stderr b/tests/ui/consts/const-compare-bytes-ub.stderr
index d8971eb..9e49706 100644
--- a/tests/ui/consts/const-compare-bytes-ub.stderr
+++ b/tests/ui/consts/const-compare-bytes-ub.stderr
@@ -1,14 +1,14 @@
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-compare-bytes-ub.rs:10:9
    |
-LL |         compare_bytes(0 as *const u8, 2 as *const u8, 0)
+LL |         compare_bytes(0 as *const u8, 2 as *const u8, 1)
    |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-compare-bytes-ub.rs:14:9
    |
-LL |         compare_bytes(1 as *const u8, 0 as *const u8, 0)
-   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance)
+LL |         compare_bytes(1 as *const u8, 0 as *const u8, 1)
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: 0x1[noalloc] is a dangling pointer (it has no provenance)
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/const-compare-bytes-ub.rs:18:9
diff --git a/tests/ui/consts/copy-intrinsic.rs b/tests/ui/consts/copy-intrinsic.rs
index 94d7bdc..4183dc0 100644
--- a/tests/ui/consts/copy-intrinsic.rs
+++ b/tests/ui/consts/copy-intrinsic.rs
@@ -23,16 +23,20 @@
 const COPY_OOB_1: () = unsafe {
     let mut x = 0i32;
     let dangle = (&mut x as *mut i32).wrapping_add(10);
-    // Even if the first ptr is an int ptr and this is a ZST copy, we should detect dangling 2nd ptrs.
-    copy_nonoverlapping(0x100 as *const i32, dangle, 0); //~ ERROR evaluation of constant value failed [E0080]
-    //~| pointer at offset 40 is out-of-bounds
+    // Zero-sized copy is fine.
+    copy_nonoverlapping(0x100 as *const i32, dangle, 0);
+    // Non-zero-sized copy is not.
+    copy_nonoverlapping(0x100 as *const i32, dangle, 1); //~ ERROR evaluation of constant value failed [E0080]
+    //~| 0x100[noalloc] is a dangling pointer
 };
 const COPY_OOB_2: () = unsafe {
     let x = 0i32;
     let dangle = (&x as *const i32).wrapping_add(10);
-    // Even if the second ptr is an int ptr and this is a ZST copy, we should detect dangling 1st ptrs.
-    copy_nonoverlapping(dangle, 0x100 as *mut i32, 0); //~ ERROR evaluation of constant value failed [E0080]
-    //~| pointer at offset 40 is out-of-bounds
+    // Zero-sized copy is fine.
+    copy_nonoverlapping(dangle, 0x100 as *mut i32, 0);
+    // Non-zero-sized copy is not.
+    copy_nonoverlapping(dangle, 0x100 as *mut i32, 1); //~ ERROR evaluation of constant value failed [E0080]
+    //~| offset 40 is out-of-bounds
 };
 
 const COPY_SIZE_OVERFLOW: () = unsafe {
diff --git a/tests/ui/consts/copy-intrinsic.stderr b/tests/ui/consts/copy-intrinsic.stderr
index 0e4e6a6..d34e61c 100644
--- a/tests/ui/consts/copy-intrinsic.stderr
+++ b/tests/ui/consts/copy-intrinsic.stderr
@@ -1,23 +1,23 @@
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:27:5
+  --> $DIR/copy-intrinsic.rs:29:5
    |
-LL |     copy_nonoverlapping(0x100 as *const i32, dangle, 0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC0 has size 4, so pointer at offset 40 is out-of-bounds
+LL |     copy_nonoverlapping(0x100 as *const i32, dangle, 1);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: 0x100[noalloc] is a dangling pointer (it has no provenance)
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:34:5
+  --> $DIR/copy-intrinsic.rs:38:5
    |
-LL |     copy_nonoverlapping(dangle, 0x100 as *mut i32, 0);
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC1 has size 4, so pointer at offset 40 is out-of-bounds
+LL |     copy_nonoverlapping(dangle, 0x100 as *mut i32, 1);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: ALLOC0 has size 4, so pointer to 4 bytes starting at offset 40 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:41:5
+  --> $DIR/copy-intrinsic.rs:45:5
    |
 LL |     copy(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy`
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/copy-intrinsic.rs:47:5
+  --> $DIR/copy-intrinsic.rs:51:5
    |
 LL |     copy_nonoverlapping(&x, &mut y, 1usize << (mem::size_of::<usize>() * 8 - 1));
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy_nonoverlapping`
diff --git a/tests/ui/consts/dangling-alloc-id-ice.rs b/tests/ui/consts/dangling-alloc-id-ice.rs
index 76d6f33..6b07b8b 100644
--- a/tests/ui/consts/dangling-alloc-id-ice.rs
+++ b/tests/ui/consts/dangling-alloc-id-ice.rs
@@ -10,7 +10,7 @@
 }
 
 const FOO: &() = {
-    //~^ ERROR it is undefined behavior to use this value
+    //~^ ERROR encountered dangling pointer
     let y = ();
     unsafe { Foo { y: &y }.long_live_the_unit }
 };
diff --git a/tests/ui/consts/dangling-alloc-id-ice.stderr b/tests/ui/consts/dangling-alloc-id-ice.stderr
index 881c0b1..de31acf 100644
--- a/tests/ui/consts/dangling-alloc-id-ice.stderr
+++ b/tests/ui/consts/dangling-alloc-id-ice.stderr
@@ -1,14 +1,8 @@
-error[E0080]: it is undefined behavior to use this value
+error: encountered dangling pointer in final value of constant
   --> $DIR/dangling-alloc-id-ice.rs:12:1
    |
 LL | const FOO: &() = {
-   | ^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free)
-   |
-   = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
-   = note: the raw bytes of the constant (size: $SIZE, align: $ALIGN) {
-               HEX_DUMP
-           }
+   | ^^^^^^^^^^^^^^
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/offset_from_ub.rs b/tests/ui/consts/offset_from_ub.rs
index 51163e6..57767e9 100644
--- a/tests/ui/consts/offset_from_ub.rs
+++ b/tests/ui/consts/offset_from_ub.rs
@@ -34,15 +34,15 @@
 
 pub const OFFSET_FROM_NULL: isize = {
     let ptr = 0 as *const u8;
-    unsafe { ptr_offset_from(ptr, ptr) } //~ERROR evaluation of constant value failed
-    //~| null pointer is a dangling pointer
+    // Null isn't special for zero-sized "accesses" (i.e., the range between the two pointers)
+    unsafe { ptr_offset_from(ptr, ptr) }
 };
 
 pub const DIFFERENT_INT: isize = { // offset_from with two different integers: like DIFFERENT_ALLOC
     let ptr1 = 8 as *const u8;
     let ptr2 = 16 as *const u8;
     unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed
-    //~| 0x8[noalloc] is a dangling pointer
+    //~| different pointers without provenance
 };
 
 const OUT_OF_BOUNDS_1: isize = {
@@ -67,8 +67,8 @@
     let start_ptr = &4 as *const _ as *const u8;
     let length = 10;
     let end_ptr = (start_ptr).wrapping_add(length);
-    unsafe { ptr_offset_from(end_ptr, end_ptr) } //~ERROR evaluation of constant value failed
-    //~| pointer at offset 10 is out-of-bounds
+    // Out-of-bounds is fine as long as the range between the pointers is empty.
+    unsafe { ptr_offset_from(end_ptr, end_ptr) }
 };
 
 pub const DIFFERENT_ALLOC_UNSIGNED: usize = {
@@ -81,13 +81,13 @@
 };
 
 pub const TOO_FAR_APART1: isize = {
-    let ptr1 = ptr::null::<u8>();
+    let ptr1 = &0u8 as *const u8;
     let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
     unsafe { ptr_offset_from(ptr2, ptr1) } //~ERROR evaluation of constant value failed
     //~| too far ahead
 };
 pub const TOO_FAR_APART2: isize = {
-    let ptr1 = ptr::null::<u8>();
+    let ptr1 = &0u8 as *const u8;
     let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
     unsafe { ptr_offset_from(ptr1, ptr2) } //~ERROR evaluation of constant value failed
     //~| too far before
@@ -100,7 +100,7 @@
     //~| first pointer has smaller offset than second: 0 < 8
 };
 pub const TOO_FAR_APART_UNSIGNED: usize = {
-    let ptr1 = ptr::null::<u8>();
+    let ptr1 = &0u8 as *const u8;
     let ptr2 = ptr1.wrapping_add(isize::MAX as usize + 42);
     // This would fit into a `usize` but we still don't allow it.
     unsafe { ptr_offset_from_unsigned(ptr2, ptr1) } //~ERROR evaluation of constant value failed
diff --git a/tests/ui/consts/offset_from_ub.stderr b/tests/ui/consts/offset_from_ub.stderr
index 4fbb2f0..65f75a6 100644
--- a/tests/ui/consts/offset_from_ub.stderr
+++ b/tests/ui/consts/offset_from_ub.stderr
@@ -24,16 +24,10 @@
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 1_isize cannot be divided by 2_isize without remainder
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:37:14
-   |
-LL |     unsafe { ptr_offset_from(ptr, ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: null pointer is a dangling pointer (it has no provenance)
-
-error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:44:14
    |
 LL |     unsafe { ptr_offset_from(ptr2, ptr1) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: 0x8[noalloc] is a dangling pointer (it has no provenance)
+   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
 
 error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:53:14
@@ -48,12 +42,6 @@
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC1 has size 4, so pointer to 10 bytes starting at offset 0 is out-of-bounds
 
 error[E0080]: evaluation of constant value failed
-  --> $DIR/offset_from_ub.rs:70:14
-   |
-LL |     unsafe { ptr_offset_from(end_ptr, end_ptr) }
-   |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds `offset_from`: ALLOC2 has size 4, so pointer at offset 10 is out-of-bounds
-
-error[E0080]: evaluation of constant value failed
   --> $DIR/offset_from_ub.rs:79:14
    |
 LL |     unsafe { ptr_offset_from_unsigned(field_ptr, base_ptr) }
@@ -86,7 +74,7 @@
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: out-of-bounds `offset_from`: null pointer is a dangling pointer (it has no provenance)
+   = note: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
    |
 note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -99,7 +87,7 @@
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: out-of-bounds `offset_from`: null pointer is a dangling pointer (it has no provenance)
+   = note: `ptr_offset_from` called on different pointers without provenance (i.e., without an associated allocation)
    |
 note: inside `std::ptr::const_ptr::<impl *const u8>::offset_from`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@@ -109,6 +97,6 @@
 LL |     unsafe { ptr1.offset_from(ptr2.wrapping_offset(1)) }
    |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 15 previous errors
+error: aborting due to 13 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/offset_ub.rs b/tests/ui/consts/offset_ub.rs
index 920ecb6..36e4ff1 100644
--- a/tests/ui/consts/offset_ub.rs
+++ b/tests/ui/consts/offset_ub.rs
@@ -17,10 +17,10 @@
 pub const ZERO_SIZED_ALLOC: *const u8 = unsafe { [0u8; 0].as_ptr().offset(1) }; //~NOTE
 pub const DANGLING: *const u8 = unsafe { ptr::NonNull::<u8>::dangling().as_ptr().offset(4) }; //~NOTE
 
-// Right now, a zero offset from null is UB
-pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::<u8>().offset(0) }; //~NOTE
-
 // Make sure that we don't panic when computing abs(offset*size_of::<T>())
 pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) }; //~NOTE
 
+// Offset-by-zero is allowed.
+pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::<u8>().offset(0) };
+
 fn main() {}
diff --git a/tests/ui/consts/offset_ub.stderr b/tests/ui/consts/offset_ub.stderr
index b398b20..89371f0 100644
--- a/tests/ui/consts/offset_ub.stderr
+++ b/tests/ui/consts/offset_ub.stderr
@@ -131,29 +131,16 @@
 error[E0080]: evaluation of constant value failed
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
    |
-   = note: out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance)
-   |
-note: inside `std::ptr::const_ptr::<impl *const u8>::offset`
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-note: inside `NULL_OFFSET_ZERO`
-  --> $DIR/offset_ub.rs:21:50
-   |
-LL | pub const NULL_OFFSET_ZERO: *const u8 = unsafe { ptr::null::<u8>().offset(0) };
-   |                                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error[E0080]: evaluation of constant value failed
-  --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
-   |
    = note: out-of-bounds pointer arithmetic: 0x7f..f[noalloc] is a dangling pointer (it has no provenance)
    |
 note: inside `std::ptr::const_ptr::<impl *const u8>::offset`
   --> $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
 note: inside `UNDERFLOW_ABS`
-  --> $DIR/offset_ub.rs:24:47
+  --> $DIR/offset_ub.rs:21:47
    |
 LL | pub const UNDERFLOW_ABS: *const u8 = unsafe { (usize::MAX as *const u8).offset(isize::MIN) };
    |                                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 12 previous errors
+error: aborting due to 11 previous errors
 
 For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs b/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs
new file mode 100644
index 0000000..5d93db5
--- /dev/null
+++ b/tests/ui/coroutine/break-inside-coroutine-issue-124495.rs
@@ -0,0 +1,26 @@
+//@ edition: 2024
+//@ compile-flags: -Z unstable-options
+
+#![feature(gen_blocks)]
+#![feature(async_closure)]
+
+async fn async_fn() {
+    break; //~ ERROR `break` inside `async` function
+}
+
+gen fn gen_fn() {
+    break; //~ ERROR `break` inside `gen` function
+}
+
+async gen fn async_gen_fn() {
+    break; //~ ERROR `break` inside `async gen` function
+}
+
+fn main() {
+    let _ = async { break; }; //~ ERROR `break` inside `async` block
+    let _ = async || { break; }; //~ ERROR `break` inside `async` closure
+
+    let _ = gen { break; }; //~ ERROR `break` inside `gen` block
+
+    let _ = async gen { break; }; //~ ERROR `break` inside `async gen` block
+}
diff --git a/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr b/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr
new file mode 100644
index 0000000..a7f37fa
--- /dev/null
+++ b/tests/ui/coroutine/break-inside-coroutine-issue-124495.stderr
@@ -0,0 +1,69 @@
+error[E0267]: `break` inside `async` function
+  --> $DIR/break-inside-coroutine-issue-124495.rs:8:5
+   |
+LL |   async fn async_fn() {
+   |  _____________________-
+LL | |     break;
+   | |     ^^^^^ cannot `break` inside `async` function
+LL | | }
+   | |_- enclosing `async` function
+
+error[E0267]: `break` inside `gen` function
+  --> $DIR/break-inside-coroutine-issue-124495.rs:12:5
+   |
+LL |   gen fn gen_fn() {
+   |  _________________-
+LL | |     break;
+   | |     ^^^^^ cannot `break` inside `gen` function
+LL | | }
+   | |_- enclosing `gen` function
+
+error[E0267]: `break` inside `async gen` function
+  --> $DIR/break-inside-coroutine-issue-124495.rs:16:5
+   |
+LL |   async gen fn async_gen_fn() {
+   |  _____________________________-
+LL | |     break;
+   | |     ^^^^^ cannot `break` inside `async gen` function
+LL | | }
+   | |_- enclosing `async gen` function
+
+error[E0267]: `break` inside `async` block
+  --> $DIR/break-inside-coroutine-issue-124495.rs:20:21
+   |
+LL |     let _ = async { break; };
+   |             --------^^^^^---
+   |             |       |
+   |             |       cannot `break` inside `async` block
+   |             enclosing `async` block
+
+error[E0267]: `break` inside `async` closure
+  --> $DIR/break-inside-coroutine-issue-124495.rs:21:24
+   |
+LL |     let _ = async || { break; };
+   |                      --^^^^^---
+   |                      | |
+   |                      | cannot `break` inside `async` closure
+   |                      enclosing `async` closure
+
+error[E0267]: `break` inside `gen` block
+  --> $DIR/break-inside-coroutine-issue-124495.rs:23:19
+   |
+LL |     let _ = gen { break; };
+   |             ------^^^^^---
+   |             |     |
+   |             |     cannot `break` inside `gen` block
+   |             enclosing `gen` block
+
+error[E0267]: `break` inside `async gen` block
+  --> $DIR/break-inside-coroutine-issue-124495.rs:25:25
+   |
+LL |     let _ = async gen { break; };
+   |             ------------^^^^^---
+   |             |           |
+   |             |           cannot `break` inside `async gen` block
+   |             enclosing `async gen` block
+
+error: aborting due to 7 previous errors
+
+For more information about this error, try `rustc --explain E0267`.
diff --git a/tests/ui/coroutine/static-move-suggestion.fixed b/tests/ui/coroutine/static-move-suggestion.fixed
new file mode 100644
index 0000000..56445be
--- /dev/null
+++ b/tests/ui/coroutine/static-move-suggestion.fixed
@@ -0,0 +1,19 @@
+//@ run-rustfix
+
+// check to make sure that we suggest adding `move` after `static`
+
+#![feature(coroutines)]
+
+fn check() -> impl Sized {
+    let x = 0;
+    #[coroutine]
+    static move || {
+        //~^ ERROR E0373
+        yield;
+        x
+    }
+}
+
+fn main() {
+    check();
+}
diff --git a/tests/ui/coroutine/static-move-suggestion.rs b/tests/ui/coroutine/static-move-suggestion.rs
new file mode 100644
index 0000000..1d6e4a6
--- /dev/null
+++ b/tests/ui/coroutine/static-move-suggestion.rs
@@ -0,0 +1,19 @@
+//@ run-rustfix
+
+// check to make sure that we suggest adding `move` after `static`
+
+#![feature(coroutines)]
+
+fn check() -> impl Sized {
+    let x = 0;
+    #[coroutine]
+    static || {
+        //~^ ERROR E0373
+        yield;
+        x
+    }
+}
+
+fn main() {
+    check();
+}
diff --git a/tests/ui/coroutine/static-move-suggestion.stderr b/tests/ui/coroutine/static-move-suggestion.stderr
new file mode 100644
index 0000000..6d89046
--- /dev/null
+++ b/tests/ui/coroutine/static-move-suggestion.stderr
@@ -0,0 +1,26 @@
+error[E0373]: coroutine may outlive the current function, but it borrows `x`, which is owned by the current function
+  --> $DIR/static-move-suggestion.rs:10:5
+   |
+LL |     static || {
+   |     ^^^^^^^^^ may outlive borrowed value `x`
+...
+LL |         x
+   |         - `x` is borrowed here
+   |
+note: coroutine is returned here
+  --> $DIR/static-move-suggestion.rs:10:5
+   |
+LL | /     static || {
+LL | |
+LL | |         yield;
+LL | |         x
+LL | |     }
+   | |_____^
+help: to force the coroutine to take ownership of `x` (and any other referenced variables), use the `move` keyword
+   |
+LL |     static move || {
+   |            ++++
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0373`.
diff --git a/tests/ui/cross-crate/xcrate-address-insignificant.rs b/tests/ui/cross-crate/address-insignificant.rs
similarity index 100%
rename from tests/ui/cross-crate/xcrate-address-insignificant.rs
rename to tests/ui/cross-crate/address-insignificant.rs
diff --git a/tests/ui/cross-crate/xcrate-associated-type-defaults.rs b/tests/ui/cross-crate/associated-type-defaults.rs
similarity index 100%
rename from tests/ui/cross-crate/xcrate-associated-type-defaults.rs
rename to tests/ui/cross-crate/associated-type-defaults.rs
diff --git a/tests/ui/xcrate/auxiliary/static_priv_by_default.rs b/tests/ui/cross-crate/auxiliary/static_priv_by_default.rs
similarity index 100%
rename from tests/ui/xcrate/auxiliary/static_priv_by_default.rs
rename to tests/ui/cross-crate/auxiliary/static_priv_by_default.rs
diff --git a/tests/ui/xcrate/auxiliary/xcrate_unit_struct.rs b/tests/ui/cross-crate/auxiliary/xcrate_unit_struct.rs
similarity index 100%
rename from tests/ui/xcrate/auxiliary/xcrate_unit_struct.rs
rename to tests/ui/cross-crate/auxiliary/xcrate_unit_struct.rs
diff --git a/tests/ui/cross-crate/xcrate_generic_fn_nested_return.rs b/tests/ui/cross-crate/generic_fn_nested_return.rs
similarity index 100%
rename from tests/ui/cross-crate/xcrate_generic_fn_nested_return.rs
rename to tests/ui/cross-crate/generic_fn_nested_return.rs
diff --git a/tests/ui/xcrate/xcrate-private-by-default.rs b/tests/ui/cross-crate/private-by-default.rs
similarity index 100%
rename from tests/ui/xcrate/xcrate-private-by-default.rs
rename to tests/ui/cross-crate/private-by-default.rs
diff --git a/tests/ui/xcrate/xcrate-private-by-default.stderr b/tests/ui/cross-crate/private-by-default.stderr
similarity index 87%
rename from tests/ui/xcrate/xcrate-private-by-default.stderr
rename to tests/ui/cross-crate/private-by-default.stderr
index 25bbbf5..398c908 100644
--- a/tests/ui/xcrate/xcrate-private-by-default.stderr
+++ b/tests/ui/cross-crate/private-by-default.stderr
@@ -1,5 +1,5 @@
 error[E0603]: static `j` is private
-  --> $DIR/xcrate-private-by-default.rs:23:29
+  --> $DIR/private-by-default.rs:23:29
    |
 LL |     static_priv_by_default::j;
    |                             ^ private static
@@ -11,7 +11,7 @@
    | ^^^^^^^^^^^^^^^
 
 error[E0603]: function `k` is private
-  --> $DIR/xcrate-private-by-default.rs:25:29
+  --> $DIR/private-by-default.rs:25:29
    |
 LL |     static_priv_by_default::k;
    |                             ^ private function
@@ -23,7 +23,7 @@
    | ^^^^^^
 
 error[E0603]: unit struct `l` is private
-  --> $DIR/xcrate-private-by-default.rs:27:29
+  --> $DIR/private-by-default.rs:27:29
    |
 LL |     static_priv_by_default::l;
    |                             ^ private unit struct
@@ -35,7 +35,7 @@
    | ^^^^^^^^
 
 error[E0603]: enum `m` is private
-  --> $DIR/xcrate-private-by-default.rs:29:35
+  --> $DIR/private-by-default.rs:29:35
    |
 LL |     foo::<static_priv_by_default::m>();
    |                                   ^ private enum
@@ -47,7 +47,7 @@
    | ^^^^^^
 
 error[E0603]: type alias `n` is private
-  --> $DIR/xcrate-private-by-default.rs:31:35
+  --> $DIR/private-by-default.rs:31:35
    |
 LL |     foo::<static_priv_by_default::n>();
    |                                   ^ private type alias
@@ -59,7 +59,7 @@
    | ^^^^^^
 
 error[E0603]: module `foo` is private
-  --> $DIR/xcrate-private-by-default.rs:35:29
+  --> $DIR/private-by-default.rs:35:29
    |
 LL |     static_priv_by_default::foo::a;
    |                             ^^^  - static `a` is not publicly re-exported
@@ -73,7 +73,7 @@
    | ^^^^^^^
 
 error[E0603]: module `foo` is private
-  --> $DIR/xcrate-private-by-default.rs:37:29
+  --> $DIR/private-by-default.rs:37:29
    |
 LL |     static_priv_by_default::foo::b;
    |                             ^^^  - function `b` is not publicly re-exported
@@ -87,7 +87,7 @@
    | ^^^^^^^
 
 error[E0603]: module `foo` is private
-  --> $DIR/xcrate-private-by-default.rs:39:29
+  --> $DIR/private-by-default.rs:39:29
    |
 LL |     static_priv_by_default::foo::c;
    |                             ^^^  - unit struct `c` is not publicly re-exported
@@ -101,7 +101,7 @@
    | ^^^^^^^
 
 error[E0603]: module `foo` is private
-  --> $DIR/xcrate-private-by-default.rs:41:35
+  --> $DIR/private-by-default.rs:41:35
    |
 LL |     foo::<static_priv_by_default::foo::d>();
    |                                   ^^^  - enum `d` is not publicly re-exported
@@ -115,7 +115,7 @@
    | ^^^^^^^
 
 error[E0603]: module `foo` is private
-  --> $DIR/xcrate-private-by-default.rs:43:35
+  --> $DIR/private-by-default.rs:43:35
    |
 LL |     foo::<static_priv_by_default::foo::e>();
    |                                   ^^^  - type alias `e` is not publicly re-exported
diff --git a/tests/ui/cross-crate/xcrate-static-addresses.rs b/tests/ui/cross-crate/static-addresses.rs
similarity index 100%
rename from tests/ui/cross-crate/xcrate-static-addresses.rs
rename to tests/ui/cross-crate/static-addresses.rs
diff --git a/tests/ui/cross-crate/xcrate-trait-lifetime-param.rs b/tests/ui/cross-crate/trait-lifetime-param.rs
similarity index 100%
rename from tests/ui/cross-crate/xcrate-trait-lifetime-param.rs
rename to tests/ui/cross-crate/trait-lifetime-param.rs
diff --git a/tests/ui/xcrate/xcrate-unit-struct-2.rs b/tests/ui/cross-crate/unit-struct-2.rs
similarity index 100%
rename from tests/ui/xcrate/xcrate-unit-struct-2.rs
rename to tests/ui/cross-crate/unit-struct-2.rs
diff --git a/tests/ui/xcrate/xcrate-unit-struct.rs b/tests/ui/cross-crate/unit-struct.rs
similarity index 100%
rename from tests/ui/xcrate/xcrate-unit-struct.rs
rename to tests/ui/cross-crate/unit-struct.rs
diff --git a/tests/ui/xcrate/xcrate-unit-struct.stderr b/tests/ui/cross-crate/unit-struct.stderr
similarity index 92%
rename from tests/ui/xcrate/xcrate-unit-struct.stderr
rename to tests/ui/cross-crate/unit-struct.stderr
index 7365170..a7e3e46 100644
--- a/tests/ui/xcrate/xcrate-unit-struct.stderr
+++ b/tests/ui/cross-crate/unit-struct.stderr
@@ -1,5 +1,5 @@
 error[E0423]: expected value, found struct `xcrate_unit_struct::StructWithFields`
-  --> $DIR/xcrate-unit-struct.rs:9:13
+  --> $DIR/unit-struct.rs:9:13
    |
 LL |     let _ = xcrate_unit_struct::StructWithFields;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use struct literal syntax instead: `xcrate_unit_struct::StructWithFields { foo: val }`
@@ -10,7 +10,7 @@
    | --------------------------- `xcrate_unit_struct::StructWithFields` defined here
 
 error[E0423]: expected value, found struct `xcrate_unit_struct::StructWithPrivFields`
-  --> $DIR/xcrate-unit-struct.rs:11:13
+  --> $DIR/unit-struct.rs:11:13
    |
 LL |     let _ = xcrate_unit_struct::StructWithPrivFields;
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/delegation/bad-resolve.rs b/tests/ui/delegation/bad-resolve.rs
index d2723dc..f378e05 100644
--- a/tests/ui/delegation/bad-resolve.rs
+++ b/tests/ui/delegation/bad-resolve.rs
@@ -36,4 +36,8 @@
     //~^ ERROR cannot find function `foo` in this scope
 }
 
+mod prefix {}
+reuse unresolved_prefix::{a, b, c}; //~ ERROR use of undeclared crate or module `unresolved_prefix`
+reuse prefix::{self, super, crate}; //~ ERROR `crate` in paths can only be used in start position
+
 fn main() {}
diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr
index f669ac3..883ff52 100644
--- a/tests/ui/delegation/bad-resolve.stderr
+++ b/tests/ui/delegation/bad-resolve.stderr
@@ -63,7 +63,19 @@
 LL | impl Trait for S {
    | ^^^^^^^^^^^^^^^^ missing `Type` in implementation
 
-error: aborting due to 8 previous errors
+error[E0433]: failed to resolve: use of undeclared crate or module `unresolved_prefix`
+  --> $DIR/bad-resolve.rs:40:7
+   |
+LL | reuse unresolved_prefix::{a, b, c};
+   |       ^^^^^^^^^^^^^^^^^ use of undeclared crate or module `unresolved_prefix`
 
-Some errors have detailed explanations: E0046, E0324, E0407, E0423, E0425, E0575, E0576.
+error[E0433]: failed to resolve: `crate` in paths can only be used in start position
+  --> $DIR/bad-resolve.rs:41:29
+   |
+LL | reuse prefix::{self, super, crate};
+   |                             ^^^^^ `crate` in paths can only be used in start position
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0046, E0324, E0407, E0423, E0425, E0433, E0575, E0576.
 For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/delegation/body-identity-list.rs b/tests/ui/delegation/body-identity-list.rs
new file mode 100644
index 0000000..1f08ab4
--- /dev/null
+++ b/tests/ui/delegation/body-identity-list.rs
@@ -0,0 +1,32 @@
+//@ check-pass
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+trait Trait {
+    fn foo(&self) {}
+    fn bar(&self) {}
+}
+
+impl Trait for u8 {}
+
+struct S(u8);
+
+mod to_import {
+    pub fn check(arg: &u8) -> &u8 { arg }
+}
+
+impl Trait for S {
+    reuse Trait::{foo, bar} {
+        use to_import::check;
+
+        let _arr = Some(self.0).map(|x| [x * 2; 3]);
+        check(&self.0)
+    }
+}
+
+fn main() {
+    let s = S(0);
+    s.foo();
+    s.bar();
+}
diff --git a/tests/ui/delegation/empty-list.rs b/tests/ui/delegation/empty-list.rs
new file mode 100644
index 0000000..e0697f4
--- /dev/null
+++ b/tests/ui/delegation/empty-list.rs
@@ -0,0 +1,8 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+mod m {}
+
+reuse m::{}; //~ ERROR empty list delegation is not supported
+
+fn main() {}
diff --git a/tests/ui/delegation/empty-list.stderr b/tests/ui/delegation/empty-list.stderr
new file mode 100644
index 0000000..50d3c0e
--- /dev/null
+++ b/tests/ui/delegation/empty-list.stderr
@@ -0,0 +1,8 @@
+error: empty list delegation is not supported
+  --> $DIR/empty-list.rs:6:1
+   |
+LL | reuse m::{};
+   | ^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/delegation/inner-attr.rs b/tests/ui/delegation/inner-attr.rs
new file mode 100644
index 0000000..6c99680
--- /dev/null
+++ b/tests/ui/delegation/inner-attr.rs
@@ -0,0 +1,8 @@
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+fn a() {}
+
+reuse a as b { #![rustc_dummy] self } //~ ERROR an inner attribute is not permitted in this context
+
+fn main() {}
diff --git a/tests/ui/delegation/inner-attr.stderr b/tests/ui/delegation/inner-attr.stderr
new file mode 100644
index 0000000..f3b53e3
--- /dev/null
+++ b/tests/ui/delegation/inner-attr.stderr
@@ -0,0 +1,18 @@
+error: an inner attribute is not permitted in this context
+  --> $DIR/inner-attr.rs:6:16
+   |
+LL | reuse a as b { #![rustc_dummy] self }
+   |                ^^^^^^^^^^^^^^^
+LL |
+LL | fn main() {}
+   | ------------ the inner attribute doesn't annotate this function
+   |
+   = note: inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
+help: to annotate the function, change the attribute from inner to outer style
+   |
+LL - reuse a as b { #![rustc_dummy] self }
+LL + reuse a as b { #[rustc_dummy] self }
+   |
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/delegation/list.rs b/tests/ui/delegation/list.rs
new file mode 100644
index 0000000..208b148
--- /dev/null
+++ b/tests/ui/delegation/list.rs
@@ -0,0 +1,46 @@
+//@ check-pass
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+trait Trait {
+    fn foo(&self) -> u8 { 0 }
+    fn bar(&self) -> u8 { 1 }
+}
+
+impl Trait for u8 {}
+
+struct S(u8);
+struct Z(u8);
+
+impl Trait for S {
+    reuse Trait::{foo, bar} { &self.0 }
+}
+
+impl Trait for Z {
+    reuse <u8 as Trait>::{foo, bar} { &self.0 }
+}
+
+trait Trait2 where Self: Trait {
+    reuse Trait::{foo, bar};
+}
+
+mod to_reuse {
+    pub fn a() {}
+    pub fn b() {}
+}
+
+reuse to_reuse::{a, b};
+
+fn main() {
+    let s = S(2);
+    s.foo();
+    s.bar();
+
+    let z = Z(3);
+    z.foo();
+    z.bar();
+
+    a();
+    b();
+}
diff --git a/tests/ui/delegation/macro-inside-list.rs b/tests/ui/delegation/macro-inside-list.rs
new file mode 100644
index 0000000..16c74d3
--- /dev/null
+++ b/tests/ui/delegation/macro-inside-list.rs
@@ -0,0 +1,26 @@
+//@ check-pass
+
+#![feature(fn_delegation)]
+#![allow(incomplete_features)]
+
+trait Trait {
+    fn foo(&self) -> u8 { 0 }
+    fn bar(&self) -> u8 { 1 }
+}
+
+impl Trait for u8 {}
+
+struct S(u8);
+
+// Macro expansion works inside delegation items.
+macro_rules! u8 { () => { u8 } }
+macro_rules! self_0 { () => { &self.0 } }
+impl Trait for S {
+    reuse <u8!() as Trait>::{foo, bar} { self_0!() }
+}
+
+fn main() {
+    let s = S(2);
+    s.foo();
+    s.bar();
+}
diff --git a/tests/ui/delegation/rename.rs b/tests/ui/delegation/rename.rs
index f4b3da7..80b8724 100644
--- a/tests/ui/delegation/rename.rs
+++ b/tests/ui/delegation/rename.rs
@@ -5,16 +5,23 @@
 
 mod to_reuse {
     pub fn a() {}
+    pub fn b() {}
 }
 
-reuse to_reuse::a as b;
+reuse to_reuse::a as x;
+reuse to_reuse::{a as y, b as z};
 
 struct S;
 impl S {
-    reuse to_reuse::a as b;
+    reuse to_reuse::a as x;
+    reuse to_reuse::{a as y, b as z};
 }
 
 fn main() {
-    b();
-    S::b();
+    x();
+    y();
+    z();
+    S::x();
+    S::y();
+    S::z();
 }
diff --git a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr
index 078c766..a030da5 100644
--- a/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr
+++ b/tests/ui/deprecation/issue-66340-deprecated-attr-non-meta-grammar.stderr
@@ -4,7 +4,7 @@
 LL | #[deprecated(note = test)]
    |                     ^^^^
    |
-help: surround the identifier with quotation marks to parse it as a string
+help: surround the identifier with quotation marks to make it into a string literal
    |
 LL | #[deprecated(note = "test")]
    |                     +    +
diff --git a/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr b/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr
index d0b14ef..e88a523 100644
--- a/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr
+++ b/tests/ui/derives/derives-span-PartialEq-enum-struct-variant.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `==` cannot be applied to type `Error`
+error[E0369]: binary operation `==` cannot be applied to type `&Error`
   --> $DIR/derives-span-PartialEq-enum-struct-variant.rs:9:6
    |
 LL | #[derive(PartialEq)]
diff --git a/tests/ui/derives/derives-span-PartialEq-enum.stderr b/tests/ui/derives/derives-span-PartialEq-enum.stderr
index f69451a..80b2254 100644
--- a/tests/ui/derives/derives-span-PartialEq-enum.stderr
+++ b/tests/ui/derives/derives-span-PartialEq-enum.stderr
@@ -1,4 +1,4 @@
-error[E0369]: binary operation `==` cannot be applied to type `Error`
+error[E0369]: binary operation `==` cannot be applied to type `&Error`
   --> $DIR/derives-span-PartialEq-enum.rs:9:6
    |
 LL | #[derive(PartialEq)]
diff --git a/tests/ui/derives/deriving-with-repr-packed-2.stderr b/tests/ui/derives/deriving-with-repr-packed-2.stderr
index 96f51a4..b62c67d 100644
--- a/tests/ui/derives/deriving-with-repr-packed-2.stderr
+++ b/tests/ui/derives/deriving-with-repr-packed-2.stderr
@@ -10,6 +10,14 @@
 LL |     _ = x.clone();
    |           ^^^^^ method cannot be called on `Foo<NonCopy>` due to unsatisfied trait bounds
    |
+note: there's an earlier shadowed binding `x` of type `Foo<u32>` that has method `clone` available
+  --> $DIR/deriving-with-repr-packed-2.rs:13:9
+   |
+LL |     let x: Foo<u32> = Foo(1, 2, 3);
+   |         ^ `x` of type `Foo<u32>` that has method `clone` defined earlier here
+...
+LL |     let x: Foo<NonCopy> = Foo(NonCopy, NonCopy, NonCopy);
+   |         - earlier `x` shadowed here with type `Foo<NonCopy>`
 note: the following trait bounds were not satisfied:
       `NonCopy: Clone`
       `NonCopy: Copy`
diff --git a/tests/ui/deriving/deriving-all-codegen.rs b/tests/ui/deriving/deriving-all-codegen.rs
index 498930f..6fa4f74 100644
--- a/tests/ui/deriving/deriving-all-codegen.rs
+++ b/tests/ui/deriving/deriving-all-codegen.rs
@@ -156,6 +156,20 @@
     Two(U),
 }
 
+// An enum that has variant, which does't implement `Copy`.
+#[derive(PartialEq)]
+enum NonCopyEnum {
+    // The `dyn NonCopyTrait` implements `PartialEq`, but it doesn't require `Copy`.
+    // So we cannot generate `PartialEq` with dereference.
+    NonCopyField(Box<dyn NonCopyTrait>),
+}
+trait NonCopyTrait {}
+impl PartialEq for dyn NonCopyTrait {
+    fn eq(&self, _other: &Self) -> bool {
+        true
+    }
+}
+
 // A union. Most builtin traits are not derivable for unions.
 #[derive(Clone, Copy)]
 pub union Union {
diff --git a/tests/ui/deriving/deriving-all-codegen.stdout b/tests/ui/deriving/deriving-all-codegen.stdout
index 9f8a9f3..6b69b57 100644
--- a/tests/ui/deriving/deriving-all-codegen.stdout
+++ b/tests/ui/deriving/deriving-all-codegen.stdout
@@ -876,7 +876,7 @@
     fn eq(&self, other: &Enum1) -> bool {
         match (self, other) {
             (Enum1::Single { x: __self_0 }, Enum1::Single { x: __arg1_0 }) =>
-                *__self_0 == *__arg1_0,
+                __self_0 == __arg1_0,
         }
     }
 }
@@ -1119,10 +1119,10 @@
         __self_discr == __arg1_discr &&
             match (self, other) {
                 (Mixed::R(__self_0), Mixed::R(__arg1_0)) =>
-                    *__self_0 == *__arg1_0,
+                    __self_0 == __arg1_0,
                 (Mixed::S { d1: __self_0, d2: __self_1 }, Mixed::S {
                     d1: __arg1_0, d2: __arg1_1 }) =>
-                    *__self_0 == *__arg1_0 && *__self_1 == *__arg1_1,
+                    __self_0 == __arg1_0 && __self_1 == __arg1_1,
                 _ => true,
             }
     }
@@ -1245,11 +1245,11 @@
         __self_discr == __arg1_discr &&
             match (self, other) {
                 (Fielded::X(__self_0), Fielded::X(__arg1_0)) =>
-                    *__self_0 == *__arg1_0,
+                    __self_0 == __arg1_0,
                 (Fielded::Y(__self_0), Fielded::Y(__arg1_0)) =>
-                    *__self_0 == *__arg1_0,
+                    __self_0 == __arg1_0,
                 (Fielded::Z(__self_0), Fielded::Z(__arg1_0)) =>
-                    *__self_0 == *__arg1_0,
+                    __self_0 == __arg1_0,
                 _ => unsafe { ::core::intrinsics::unreachable() }
             }
     }
@@ -1368,9 +1368,9 @@
         __self_discr == __arg1_discr &&
             match (self, other) {
                 (EnumGeneric::One(__self_0), EnumGeneric::One(__arg1_0)) =>
-                    *__self_0 == *__arg1_0,
+                    __self_0 == __arg1_0,
                 (EnumGeneric::Two(__self_0), EnumGeneric::Two(__arg1_0)) =>
-                    *__self_0 == *__arg1_0,
+                    __self_0 == __arg1_0,
                 _ => unsafe { ::core::intrinsics::unreachable() }
             }
     }
@@ -1426,6 +1426,30 @@
     }
 }
 
+// An enum that has variant, which does't implement `Copy`.
+enum NonCopyEnum {
+
+    // The `dyn NonCopyTrait` implements `PartialEq`, but it doesn't require `Copy`.
+    // So we cannot generate `PartialEq` with dereference.
+    NonCopyField(Box<dyn NonCopyTrait>),
+}
+#[automatically_derived]
+impl ::core::marker::StructuralPartialEq for NonCopyEnum { }
+#[automatically_derived]
+impl ::core::cmp::PartialEq for NonCopyEnum {
+    #[inline]
+    fn eq(&self, other: &NonCopyEnum) -> bool {
+        match (self, other) {
+            (NonCopyEnum::NonCopyField(__self_0),
+                NonCopyEnum::NonCopyField(__arg1_0)) => __self_0 == __arg1_0,
+        }
+    }
+}
+trait NonCopyTrait {}
+impl PartialEq for dyn NonCopyTrait {
+    fn eq(&self, _other: &Self) -> bool { true }
+}
+
 // A union. Most builtin traits are not derivable for unions.
 pub union Union {
     pub b: bool,
diff --git a/tests/ui/diagnostic_namespace/auxiliary/bad_on_unimplemented.rs b/tests/ui/diagnostic_namespace/auxiliary/bad_on_unimplemented.rs
index 4a5fca4..e44c7e4 100644
--- a/tests/ui/diagnostic_namespace/auxiliary/bad_on_unimplemented.rs
+++ b/tests/ui/diagnostic_namespace/auxiliary/bad_on_unimplemented.rs
@@ -1,2 +1,26 @@
 #[diagnostic::on_unimplemented(aa = "broken")]
-pub trait Test {}
+pub trait MissingAttr {}
+
+#[diagnostic::on_unimplemented(label = "a", label = "b")]
+pub trait DuplicateAttr {}
+
+#[diagnostic::on_unimplemented = "broken"]
+pub trait NotMetaList {}
+
+#[diagnostic::on_unimplemented]
+pub trait Empty {}
+
+#[diagnostic::on_unimplemented {}]
+pub trait WrongDelim {}
+
+#[diagnostic::on_unimplemented(label = "{A:.3}")]
+pub trait BadFormatter<A> {}
+
+#[diagnostic::on_unimplemented(label = "test {}")]
+pub trait NoImplicitArgs {}
+
+#[diagnostic::on_unimplemented(label = "{missing}")]
+pub trait MissingArg {}
+
+#[diagnostic::on_unimplemented(label = "{_}")]
+pub trait BadArg {}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr
new file mode 100644
index 0000000..41f222e
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.current.stderr
@@ -0,0 +1,12 @@
+error[E0277]: the trait bound `&str: AsExpression<Integer>` is not satisfied
+  --> $DIR/as_expression.rs:57:15
+   |
+LL |     SelectInt.check("bar");
+   |               ^^^^^ the trait `AsExpression<Integer>` is not implemented for `&str`
+   |
+   = help: the trait `AsExpression<Text>` is implemented for `&str`
+   = help: for that trait implementation, expected `Text`, found `Integer`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
new file mode 100644
index 0000000..47acf5b
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.next.stderr
@@ -0,0 +1,21 @@
+error[E0277]: the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
+  --> $DIR/as_expression.rs:57:21
+   |
+LL |     SelectInt.check("bar");
+   |               ----- ^^^^^ the trait `AsExpression<<SelectInt as Expression>::SqlType>` is not implemented for `&str`
+   |               |
+   |               required by a bound introduced by this call
+   |
+   = help: the trait `AsExpression<Text>` is implemented for `&str`
+note: required by a bound in `Foo::check`
+  --> $DIR/as_expression.rs:48:12
+   |
+LL |     fn check<T>(&self, _: T) -> <T as AsExpression<<Self as Expression>::SqlType>>::Expression
+   |        ----- required by a bound in this associated function
+LL |     where
+LL |         T: AsExpression<Self::SqlType>,
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Foo::check`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
new file mode 100644
index 0000000..5fd5cc5
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/as_expression.rs
@@ -0,0 +1,60 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+#![feature(do_not_recommend)]
+
+pub trait Expression {
+    type SqlType;
+}
+
+pub trait AsExpression<ST> {
+    type Expression: Expression<SqlType = ST>;
+}
+
+pub struct Text;
+pub struct Integer;
+
+pub struct Bound<T>(T);
+pub struct SelectInt;
+
+impl Expression for SelectInt {
+    type SqlType = Integer;
+}
+
+impl<T> Expression for Bound<T> {
+    type SqlType = T;
+}
+
+#[diagnostic::do_not_recommend]
+impl<T, ST> AsExpression<ST> for T
+where
+    T: Expression<SqlType = ST>,
+{
+    type Expression = T;
+}
+
+impl AsExpression<Integer> for i32 {
+    type Expression = Bound<Integer>;
+}
+
+impl AsExpression<Text> for &'_ str {
+    type Expression = Bound<Text>;
+}
+
+trait Foo: Expression + Sized {
+    fn check<T>(&self, _: T) -> <T as AsExpression<<Self as Expression>::SqlType>>::Expression
+    where
+        T: AsExpression<Self::SqlType>,
+    {
+        todo!()
+    }
+}
+
+impl<T> Foo for T where T: Expression {}
+
+fn main() {
+    SelectInt.check("bar");
+    //[next]~^ ERROR the trait bound `&str: AsExpression<<SelectInt as Expression>::SqlType>` is not satisfied
+    //[current]~^^ ERROR the trait bound `&str: AsExpression<Integer>` is not satisfied
+}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.rs b/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.rs
new file mode 100644
index 0000000..5a26d28
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.rs
@@ -0,0 +1,17 @@
+#![feature(do_not_recommend)]
+
+pub trait Foo {}
+
+impl Foo for i32 {}
+
+pub trait Bar {}
+
+#[diagnostic::do_not_recommend]
+impl<T: Foo> Bar for T {}
+
+fn stuff<T: Bar>(_: T) {}
+
+fn main() {
+    stuff(1u8);
+    //~^ the trait bound `u8: Bar` is not satisfied
+}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.stderr
new file mode 100644
index 0000000..3951231
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/feature-gate-do_not_recommend.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `u8: Bar` is not satisfied
+  --> $DIR/feature-gate-do_not_recommend.rs:15:11
+   |
+LL |     stuff(1u8);
+   |           ^^^ the trait `Bar` is not implemented for `u8`
+   |
+note: required by a bound in `stuff`
+  --> $DIR/feature-gate-do_not_recommend.rs:12:13
+   |
+LL | fn stuff<T: Bar>(_: T) {}
+   |             ^^^ required by this bound in `stuff`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs
new file mode 100644
index 0000000..400ef83
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.rs
@@ -0,0 +1,39 @@
+//@ check-pass
+#![feature(do_not_recommend)]
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+const CONST: () = ();
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+static STATIC: () = ();
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+type Type = ();
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+enum Enum {}
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+extern "C" {}
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+fn fun() {}
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+struct Struct {}
+
+#[diagnostic::do_not_recommend]
+//~^WARN `#[diagnostic::do_not_recommend]` can only be placed
+trait Trait {}
+
+#[diagnostic::do_not_recommend]
+impl Trait for i32 {}
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.stderr
new file mode 100644
index 0000000..c83fd46
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/incorrect-locations.stderr
@@ -0,0 +1,52 @@
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:4:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+   = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:8:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:12:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:16:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:20:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:24:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:28:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: `#[diagnostic::do_not_recommend]` can only be placed on trait implementations
+  --> $DIR/incorrect-locations.rs:32:1
+   |
+LL | #[diagnostic::do_not_recommend]
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+warning: 8 warnings emitted
+
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr
index a4d4b7b..729cb56 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.current.stderr
@@ -1,16 +1,11 @@
 error[E0277]: the trait bound `*mut (): Foo` is not satisfied
-  --> $DIR/simple.rs:19:17
+  --> $DIR/simple.rs:17:17
    |
 LL |     needs_foo::<*mut ()>();
-   |                 ^^^^^^^ the trait `Send` is not implemented for `*mut ()`, which is required by `*mut (): Foo`
+   |                 ^^^^^^^ the trait `Foo` is not implemented for `*mut ()`
    |
-note: required for `*mut ()` to implement `Foo`
-  --> $DIR/simple.rs:10:9
-   |
-LL | impl<T> Foo for T where T: Send {}
-   |         ^^^     ^          ---- unsatisfied trait bound introduced here
 note: required by a bound in `needs_foo`
-  --> $DIR/simple.rs:14:17
+  --> $DIR/simple.rs:12:17
    |
 LL | fn needs_foo<T: Foo>() {}
    |                 ^^^ required by this bound in `needs_foo`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr
index 1341ca8..729cb56 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.next.stderr
@@ -1,11 +1,11 @@
 error[E0277]: the trait bound `*mut (): Foo` is not satisfied
-  --> $DIR/simple.rs:19:17
+  --> $DIR/simple.rs:17:17
    |
 LL |     needs_foo::<*mut ()>();
    |                 ^^^^^^^ the trait `Foo` is not implemented for `*mut ()`
    |
 note: required by a bound in `needs_foo`
-  --> $DIR/simple.rs:14:17
+  --> $DIR/simple.rs:12:17
    |
 LL | fn needs_foo<T: Foo>() {}
    |                 ^^^ required by this bound in `needs_foo`
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs b/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs
index 15ff80a..780649b 100644
--- a/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/simple.rs
@@ -6,10 +6,8 @@
 
 trait Foo {}
 
-#[do_not_recommend]
+#[diagnostic::do_not_recommend]
 impl<T> Foo for T where T: Send {}
-//[current]~^ NOTE required for `*mut ()` to implement `Foo`
-//[current]~| NOTE unsatisfied trait bound introduced here
 
 fn needs_foo<T: Foo>() {}
 //~^ NOTE required by a bound in `needs_foo`
@@ -18,6 +16,5 @@
 fn main() {
     needs_foo::<*mut ()>();
     //~^ ERROR the trait bound `*mut (): Foo` is not satisfied
-    //[current]~| NOTE the trait `Send` is not implemented for `*mut ()`
-    //[next]~| NOTE the trait `Foo` is not implemented for `*mut ()`
+    //~| NOTE the trait `Foo` is not implemented for `*mut ()`
 }
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr
new file mode 100644
index 0000000..41a10a6
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.current.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `(): Root` is not satisfied
+  --> $DIR/stacked.rs:19:18
+   |
+LL |     needs_root::<()>();
+   |                  ^^ the trait `Root` is not implemented for `()`
+   |
+note: required by a bound in `needs_root`
+  --> $DIR/stacked.rs:16:18
+   |
+LL | fn needs_root<T: Root>() {}
+   |                  ^^^^ required by this bound in `needs_root`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr
new file mode 100644
index 0000000..41a10a6
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.next.stderr
@@ -0,0 +1,15 @@
+error[E0277]: the trait bound `(): Root` is not satisfied
+  --> $DIR/stacked.rs:19:18
+   |
+LL |     needs_root::<()>();
+   |                  ^^ the trait `Root` is not implemented for `()`
+   |
+note: required by a bound in `needs_root`
+  --> $DIR/stacked.rs:16:18
+   |
+LL | fn needs_root<T: Root>() {}
+   |                  ^^^^ required by this bound in `needs_root`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs
new file mode 100644
index 0000000..fc355bd
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/stacked.rs
@@ -0,0 +1,21 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
+#![feature(do_not_recommend)]
+
+trait Root {}
+trait DontRecommend {}
+trait Other {}
+
+#[diagnostic::do_not_recommend]
+impl<T> Root for T where T: DontRecommend {}
+
+impl<T> DontRecommend for T where T: Other {}
+
+fn needs_root<T: Root>() {}
+
+fn main() {
+    needs_root::<()>();
+    //~^ ERROR the trait bound `(): Root` is not satisfied
+}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.rs b/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.rs
new file mode 100644
index 0000000..ccc687a
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.rs
@@ -0,0 +1,8 @@
+#![deny(unknown_or_malformed_diagnostic_attributes)]
+trait Foo {}
+
+#[diagnostic::do_not_recommend]
+//~^ ERROR unknown diagnostic attribute [unknown_or_malformed_diagnostic_attributes]
+impl Foo for i32 {}
+
+fn main() {}
diff --git a/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.stderr b/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.stderr
new file mode 100644
index 0000000..d833222
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/do_not_recommend/unstable-feature.stderr
@@ -0,0 +1,14 @@
+error: unknown diagnostic attribute
+  --> $DIR/unstable-feature.rs:4:15
+   |
+LL | #[diagnostic::do_not_recommend]
+   |               ^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/unstable-feature.rs:1:9
+   |
+LL | #![deny(unknown_or_malformed_diagnostic_attributes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs
new file mode 100644
index 0000000..8b7467a
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.rs
@@ -0,0 +1,31 @@
+//@ edition:2021
+//@ aux-build:bad_on_unimplemented.rs
+
+// Do not ICE when encountering a malformed `#[diagnostic::on_unimplemented]` annotation in a
+// dependency when incorrectly used (#124651).
+
+extern crate bad_on_unimplemented;
+
+use bad_on_unimplemented::*;
+
+fn missing_attr<T: MissingAttr>(_: T) {}
+fn duplicate_attr<T: DuplicateAttr>(_: T) {}
+fn not_meta_list<T: NotMetaList>(_: T) {}
+fn empty<T: Empty>(_: T) {}
+fn wrong_delim<T: WrongDelim>(_: T) {}
+fn bad_formatter<T: BadFormatter<()>>(_: T) {}
+fn no_implicit_args<T: NoImplicitArgs>(_: T) {}
+fn missing_arg<T: MissingArg>(_: T) {}
+fn bad_arg<T: BadArg>(_: T) {}
+
+fn main() {
+    missing_attr(()); //~ ERROR E0277
+    duplicate_attr(()); //~ ERROR E0277
+    not_meta_list(()); //~ ERROR E0277
+    empty(()); //~ ERROR E0277
+    wrong_delim(()); //~ ERROR E0277
+    bad_formatter(()); //~ ERROR E0277
+    no_implicit_args(()); //~ ERROR E0277
+    missing_arg(()); //~ ERROR E0277
+    bad_arg(()); //~ ERROR E0277
+}
diff --git a/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr
new file mode 100644
index 0000000..c3e5655
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/malformed_foreign_on_unimplemented.stderr
@@ -0,0 +1,134 @@
+error[E0277]: the trait bound `(): bad_on_unimplemented::MissingAttr` is not satisfied
+  --> $DIR/malformed_foreign_on_unimplemented.rs:22:18
+   |
+LL |     missing_attr(());
+   |     ------------ ^^ the trait `bad_on_unimplemented::MissingAttr` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `missing_attr`
+  --> $DIR/malformed_foreign_on_unimplemented.rs:11:20
+   |
+LL | fn missing_attr<T: MissingAttr>(_: T) {}
+   |                    ^^^^^^^^^^^ required by this bound in `missing_attr`
+
+error[E0277]: the trait bound `(): bad_on_unimplemented::DuplicateAttr` is not satisfied
+  --> $DIR/malformed_foreign_on_unimplemented.rs:23:20
+   |
+LL |     duplicate_attr(());
+   |     -------------- ^^ a
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `bad_on_unimplemented::DuplicateAttr` is not implemented for `()`
+note: required by a bound in `duplicate_attr`
+  --> $DIR/malformed_foreign_on_unimplemented.rs:12:22
+   |
+LL | fn duplicate_attr<T: DuplicateAttr>(_: T) {}
+   |                      ^^^^^^^^^^^^^ required by this bound in `duplicate_attr`
+
+error[E0277]: the trait bound `(): bad_on_unimplemented::NotMetaList` is not satisfied
+  --> $DIR/malformed_foreign_on_unimplemented.rs:24:19
+   |
+LL |     not_meta_list(());
+   |     ------------- ^^ the trait `bad_on_unimplemented::NotMetaList` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `not_meta_list`
+  --> $DIR/malformed_foreign_on_unimplemented.rs:13:21
+   |
+LL | fn not_meta_list<T: NotMetaList>(_: T) {}
+   |                     ^^^^^^^^^^^ required by this bound in `not_meta_list`
+
+error[E0277]: the trait bound `(): bad_on_unimplemented::Empty` is not satisfied
+  --> $DIR/malformed_foreign_on_unimplemented.rs:25:11
+   |
+LL |     empty(());
+   |     ----- ^^ the trait `bad_on_unimplemented::Empty` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `empty`
+  --> $DIR/malformed_foreign_on_unimplemented.rs:14:13
+   |
+LL | fn empty<T: Empty>(_: T) {}
+   |             ^^^^^ required by this bound in `empty`
+
+error[E0277]: the trait bound `(): bad_on_unimplemented::WrongDelim` is not satisfied
+  --> $DIR/malformed_foreign_on_unimplemented.rs:26:17
+   |
+LL |     wrong_delim(());
+   |     ----------- ^^ the trait `bad_on_unimplemented::WrongDelim` is not implemented for `()`
+   |     |
+   |     required by a bound introduced by this call
+   |
+note: required by a bound in `wrong_delim`
+  --> $DIR/malformed_foreign_on_unimplemented.rs:15:19
+   |
+LL | fn wrong_delim<T: WrongDelim>(_: T) {}
+   |                   ^^^^^^^^^^ required by this bound in `wrong_delim`
+
+error[E0277]: the trait bound `(): bad_on_unimplemented::BadFormatter<()>` is not satisfied
+  --> $DIR/malformed_foreign_on_unimplemented.rs:27:19
+   |
+LL |     bad_formatter(());
+   |     ------------- ^^ ()
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `bad_on_unimplemented::BadFormatter<()>` is not implemented for `()`
+note: required by a bound in `bad_formatter`
+  --> $DIR/malformed_foreign_on_unimplemented.rs:16:21
+   |
+LL | fn bad_formatter<T: BadFormatter<()>>(_: T) {}
+   |                     ^^^^^^^^^^^^^^^^ required by this bound in `bad_formatter`
+
+error[E0277]: the trait bound `(): bad_on_unimplemented::NoImplicitArgs` is not satisfied
+  --> $DIR/malformed_foreign_on_unimplemented.rs:28:22
+   |
+LL |     no_implicit_args(());
+   |     ---------------- ^^ test {}
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `bad_on_unimplemented::NoImplicitArgs` is not implemented for `()`
+note: required by a bound in `no_implicit_args`
+  --> $DIR/malformed_foreign_on_unimplemented.rs:17:24
+   |
+LL | fn no_implicit_args<T: NoImplicitArgs>(_: T) {}
+   |                        ^^^^^^^^^^^^^^ required by this bound in `no_implicit_args`
+
+error[E0277]: the trait bound `(): bad_on_unimplemented::MissingArg` is not satisfied
+  --> $DIR/malformed_foreign_on_unimplemented.rs:29:17
+   |
+LL |     missing_arg(());
+   |     ----------- ^^ {missing}
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `bad_on_unimplemented::MissingArg` is not implemented for `()`
+note: required by a bound in `missing_arg`
+  --> $DIR/malformed_foreign_on_unimplemented.rs:18:19
+   |
+LL | fn missing_arg<T: MissingArg>(_: T) {}
+   |                   ^^^^^^^^^^ required by this bound in `missing_arg`
+
+error[E0277]: the trait bound `(): bad_on_unimplemented::BadArg` is not satisfied
+  --> $DIR/malformed_foreign_on_unimplemented.rs:30:13
+   |
+LL |     bad_arg(());
+   |     ------- ^^ {_}
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `bad_on_unimplemented::BadArg` is not implemented for `()`
+note: required by a bound in `bad_arg`
+  --> $DIR/malformed_foreign_on_unimplemented.rs:19:15
+   |
+LL | fn bad_arg<T: BadArg>(_: T) {}
+   |               ^^^^^^ required by this bound in `bad_arg`
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented_ice.rs b/tests/ui/diagnostic_namespace/on_unimplemented_ice.rs
deleted file mode 100644
index 8969f50..0000000
--- a/tests/ui/diagnostic_namespace/on_unimplemented_ice.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//@ edition:2021
-//@ compile-flags:--test
-//@ aux-build:bad_on_unimplemented.rs
-
-// Do not ICE when encountering a malformed `#[diagnostic::on_unimplemented]` annotation in a
-// dependency when incorrectly used (#124651).
-
-extern crate bad_on_unimplemented;
-
-use bad_on_unimplemented::Test;
-
-fn breakage<T: Test>(_: T) {}
-
-#[test]
-fn test() {
-    breakage(1); //~ ERROR E0277
-}
diff --git a/tests/ui/diagnostic_namespace/on_unimplemented_ice.stderr b/tests/ui/diagnostic_namespace/on_unimplemented_ice.stderr
deleted file mode 100644
index 1c0da96..0000000
--- a/tests/ui/diagnostic_namespace/on_unimplemented_ice.stderr
+++ /dev/null
@@ -1,17 +0,0 @@
-error[E0277]: the trait bound `{integer}: Test` is not satisfied
-  --> $DIR/on_unimplemented_ice.rs:16:14
-   |
-LL |     breakage(1);
-   |     -------- ^ the trait `Test` is not implemented for `{integer}`
-   |     |
-   |     required by a bound introduced by this call
-   |
-note: required by a bound in `breakage`
-  --> $DIR/on_unimplemented_ice.rs:12:16
-   |
-LL | fn breakage<T: Test>(_: T) {}
-   |                ^^^^ required by this bound in `breakage`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/diagnostic_namespace/suggest_typos.rs b/tests/ui/diagnostic_namespace/suggest_typos.rs
new file mode 100644
index 0000000..b25f097
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/suggest_typos.rs
@@ -0,0 +1,18 @@
+#![deny(unknown_or_malformed_diagnostic_attributes)]
+
+#[diagnostic::onunimplemented]
+//~^ERROR unknown diagnostic attribute
+//~^^HELP an attribute with a similar name exists
+trait X{}
+
+#[diagnostic::un_onimplemented]
+//~^ERROR unknown diagnostic attribute
+//~^^HELP an attribute with a similar name exists
+trait Y{}
+
+#[diagnostic::on_implemented]
+//~^ERROR unknown diagnostic attribute
+//~^^HELP an attribute with a similar name exists
+trait Z{}
+
+fn main(){}
diff --git a/tests/ui/diagnostic_namespace/suggest_typos.stderr b/tests/ui/diagnostic_namespace/suggest_typos.stderr
new file mode 100644
index 0000000..3073112
--- /dev/null
+++ b/tests/ui/diagnostic_namespace/suggest_typos.stderr
@@ -0,0 +1,40 @@
+error: unknown diagnostic attribute
+  --> $DIR/suggest_typos.rs:3:15
+   |
+LL | #[diagnostic::onunimplemented]
+   |               ^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/suggest_typos.rs:1:9
+   |
+LL | #![deny(unknown_or_malformed_diagnostic_attributes)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: an attribute with a similar name exists
+   |
+LL | #[diagnostic::on_unimplemented]
+   |               ~~~~~~~~~~~~~~~~
+
+error: unknown diagnostic attribute
+  --> $DIR/suggest_typos.rs:8:15
+   |
+LL | #[diagnostic::un_onimplemented]
+   |               ^^^^^^^^^^^^^^^^
+   |
+help: an attribute with a similar name exists
+   |
+LL | #[diagnostic::on_unimplemented]
+   |               ~~~~~~~~~~~~~~~~
+
+error: unknown diagnostic attribute
+  --> $DIR/suggest_typos.rs:13:15
+   |
+LL | #[diagnostic::on_implemented]
+   |               ^^^^^^^^^^^^^^
+   |
+help: an attribute with a similar name exists
+   |
+LL | #[diagnostic::on_unimplemented]
+   |               ~~~~~~~~~~~~~~~~
+
+error: aborting due to 3 previous errors
+
diff --git a/tests/ui/dyn-star/param-env-region-infer.current.stderr b/tests/ui/dyn-star/param-env-region-infer.current.stderr
index b50117c..6e464c1 100644
--- a/tests/ui/dyn-star/param-env-region-infer.current.stderr
+++ b/tests/ui/dyn-star/param-env-region-infer.current.stderr
@@ -1,5 +1,5 @@
 error[E0282]: type annotations needed
-  --> $DIR/param-env-region-infer.rs:19:10
+  --> $DIR/param-env-region-infer.rs:20:10
    |
 LL |     t as _
    |          ^ cannot infer type
diff --git a/tests/ui/dyn-star/param-env-region-infer.rs b/tests/ui/dyn-star/param-env-region-infer.rs
index c538610..842964a 100644
--- a/tests/ui/dyn-star/param-env-region-infer.rs
+++ b/tests/ui/dyn-star/param-env-region-infer.rs
@@ -1,9 +1,10 @@
 //@ revisions: current
 //@ incremental
 
-// FIXME(-Znext-solver): THis currently results in unstable query results:
+// FIXME(-Znext-solver): This currently results in unstable query results:
 // `normalizes-to(opaque, opaque)` changes from `Maybe(Ambiguous)` to `Maybe(Overflow)`
 // once the hidden type of the opaque is already defined to be itself.
+//@ unused-revision-names: next
 
 // checks that we don't ICE if there are region inference variables in the environment
 // when computing `PointerLike` builtin candidates.
diff --git a/tests/ui/env-null-vars.rs b/tests/ui/env-null-vars.rs
deleted file mode 100644
index bb86fd3..0000000
--- a/tests/ui/env-null-vars.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-//@ run-pass
-
-#![allow(unused_imports)]
-
-//@ ignore-windows
-
-// issue-53200
-
-#![feature(rustc_private)]
-extern crate libc;
-
-use std::env;
-
-// FIXME: more platforms?
-#[cfg(target_os = "linux")]
-fn main() {
-    unsafe { libc::clearenv(); }
-    assert_eq!(env::vars().count(), 0);
-}
-
-#[cfg(not(target_os = "linux"))]
-fn main() {}
diff --git a/tests/ui/error-codes/E0259.rs b/tests/ui/error-codes/E0259.rs
index e7e94d5..78e56de 100644
--- a/tests/ui/error-codes/E0259.rs
+++ b/tests/ui/error-codes/E0259.rs
@@ -1,8 +1,8 @@
-#![feature(rustc_private)]
+#![feature(test)]
 
 extern crate alloc;
 
-extern crate libc as alloc;
+extern crate test as alloc;
 //~^ ERROR E0259
 
 fn main() {}
diff --git a/tests/ui/error-codes/E0259.stderr b/tests/ui/error-codes/E0259.stderr
index 6e08626..975d1a1 100644
--- a/tests/ui/error-codes/E0259.stderr
+++ b/tests/ui/error-codes/E0259.stderr
@@ -4,13 +4,13 @@
 LL | extern crate alloc;
    | ------------------- previous import of the extern crate `alloc` here
 LL |
-LL | extern crate libc as alloc;
+LL | extern crate test as alloc;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `alloc` reimported here
    |
    = note: `alloc` must be defined only once in the type namespace of this module
 help: you can use `as` to change the binding name of the import
    |
-LL | extern crate libc as other_alloc;
+LL | extern crate test as other_alloc;
    |
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/expr-block-fn.rs b/tests/ui/expr/block-fn.rs
similarity index 100%
rename from tests/ui/expr-block-fn.rs
rename to tests/ui/expr/block-fn.rs
diff --git a/tests/ui/expr-block-generic.rs b/tests/ui/expr/block-generic.rs
similarity index 100%
rename from tests/ui/expr-block-generic.rs
rename to tests/ui/expr/block-generic.rs
diff --git a/tests/ui/expr-block.rs b/tests/ui/expr/block.rs
similarity index 100%
rename from tests/ui/expr-block.rs
rename to tests/ui/expr/block.rs
diff --git a/tests/ui/expr-copy.rs b/tests/ui/expr/copy.rs
similarity index 100%
rename from tests/ui/expr-copy.rs
rename to tests/ui/expr/copy.rs
diff --git a/tests/ui/expr-if-generic.rs b/tests/ui/expr/if-generic.rs
similarity index 100%
rename from tests/ui/expr-if-generic.rs
rename to tests/ui/expr/if-generic.rs
diff --git a/tests/ui/expr-if-panic-all.rs b/tests/ui/expr/if-panic-all.rs
similarity index 100%
rename from tests/ui/expr-if-panic-all.rs
rename to tests/ui/expr/if-panic-all.rs
diff --git a/tests/ui/expr-scope.rs b/tests/ui/expr/scope.rs
similarity index 100%
rename from tests/ui/expr-scope.rs
rename to tests/ui/expr/scope.rs
diff --git a/tests/ui/feature-gates/feature-gate-global-registration.rs b/tests/ui/feature-gates/feature-gate-global-registration.rs
new file mode 100644
index 0000000..6ac3671
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-global-registration.rs
@@ -0,0 +1,3 @@
+todo!(); //~ ERROR
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-global-registration.stderr b/tests/ui/feature-gates/feature-gate-global-registration.stderr
new file mode 100644
index 0000000..70538ae
--- /dev/null
+++ b/tests/ui/feature-gates/feature-gate-global-registration.stderr
@@ -0,0 +1,13 @@
+error: expected one of `!` or `::`, found `(`
+  --> $DIR/feature-gate-global-registration.rs:1:1
+   |
+LL | todo!();
+   | ^^^^^^^
+   | |
+   | expected one of `!` or `::`
+   | in this macro invocation
+   |
+   = note: this error originates in the macro `todo` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.rs b/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.rs
index f213e89..85c08ec 100644
--- a/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.rs
+++ b/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.rs
@@ -1,4 +1,15 @@
 const X: i32 = #[allow(dead_code)] 8;
 //~^ ERROR attributes on expressions are experimental
 
+const Y: i32 =
+    /// foo
+//~^ ERROR attributes on expressions are experimental
+    8;
+
+const Z: i32 = {
+    //! foo
+//~^ ERROR attributes on expressions are experimental
+    8
+};
+
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr b/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr
index 67fdae0..14f7d58 100644
--- a/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr
+++ b/tests/ui/feature-gates/feature-gate-stmt_expr_attributes.stderr
@@ -8,6 +8,28 @@
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 1 previous error
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/feature-gate-stmt_expr_attributes.rs:5:5
+   |
+LL |     /// foo
+   |     ^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: `///` is used for outer documentation comments; for a plain comment, use `//`
+
+error[E0658]: attributes on expressions are experimental
+  --> $DIR/feature-gate-stmt_expr_attributes.rs:10:5
+   |
+LL |     //! foo
+   |     ^^^^^^^
+   |
+   = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
+   = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+   = help: `//!` is used for inner documentation comments; for a plain comment, use `//` by removing the `!` or inserting a space in between them: `// !`
+
+error: aborting due to 3 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
index bd3b69c..ca60bc6 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.rs
@@ -45,7 +45,7 @@
     //~| NOTE not a function or closure
 
     #[inline = "2100"] fn f() { }
-    //~^ ERROR attribute must be of the form
+    //~^ ERROR valid forms for the attribute are
     //~| WARN this was previously accepted
     //~| NOTE #[deny(ill_formed_attribute_input)]` on by default
     //~| NOTE for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
index 89fa2ab..ac2bf78 100644
--- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
+++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr
@@ -7,7 +7,7 @@
    = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: attribute must be of the form `#[inline]` or `#[inline(always|never)]`
+error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]`
   --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:47:5
    |
 LL |     #[inline = "2100"] fn f() { }
diff --git a/tests/ui/feature-gates/rustc-private.rs b/tests/ui/feature-gates/rustc-private.rs
index 7b8944b..aa44f79 100644
--- a/tests/ui/feature-gates/rustc-private.rs
+++ b/tests/ui/feature-gates/rustc-private.rs
@@ -1,5 +1,5 @@
 // gate-test-rustc_private
 
-extern crate libc; //~ ERROR  use of unstable library feature 'rustc_private'
+extern crate cfg_if; //~ ERROR  use of unstable library feature 'rustc_private'
 
 fn main() {}
diff --git a/tests/ui/feature-gates/rustc-private.stderr b/tests/ui/feature-gates/rustc-private.stderr
index 03397cb..96cc986 100644
--- a/tests/ui/feature-gates/rustc-private.stderr
+++ b/tests/ui/feature-gates/rustc-private.stderr
@@ -1,8 +1,8 @@
 error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
   --> $DIR/rustc-private.rs:3:1
    |
-LL | extern crate libc;
-   | ^^^^^^^^^^^^^^^^^^
+LL | extern crate cfg_if;
+   | ^^^^^^^^^^^^^^^^^^^^
    |
    = note: see issue #27812 <https://github.com/rust-lang/rust/issues/27812> for more information
    = help: add `#![feature(rustc_private)]` to the crate attributes to enable
diff --git a/tests/ui/stmt_expr_attrs_no_feature.rs b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs
similarity index 100%
rename from tests/ui/stmt_expr_attrs_no_feature.rs
rename to tests/ui/feature-gates/stmt_expr_attrs_no_feature.rs
diff --git a/tests/ui/stmt_expr_attrs_no_feature.stderr b/tests/ui/feature-gates/stmt_expr_attrs_no_feature.stderr
similarity index 100%
rename from tests/ui/stmt_expr_attrs_no_feature.stderr
rename to tests/ui/feature-gates/stmt_expr_attrs_no_feature.stderr
diff --git a/tests/ui/ffi_const.rs b/tests/ui/ffi-attrs/ffi_const.rs
similarity index 100%
rename from tests/ui/ffi_const.rs
rename to tests/ui/ffi-attrs/ffi_const.rs
diff --git a/tests/ui/ffi_const.stderr b/tests/ui/ffi-attrs/ffi_const.stderr
similarity index 100%
rename from tests/ui/ffi_const.stderr
rename to tests/ui/ffi-attrs/ffi_const.stderr
diff --git a/tests/ui/ffi_const2.rs b/tests/ui/ffi-attrs/ffi_const2.rs
similarity index 100%
rename from tests/ui/ffi_const2.rs
rename to tests/ui/ffi-attrs/ffi_const2.rs
diff --git a/tests/ui/ffi_const2.stderr b/tests/ui/ffi-attrs/ffi_const2.stderr
similarity index 100%
rename from tests/ui/ffi_const2.stderr
rename to tests/ui/ffi-attrs/ffi_const2.stderr
diff --git a/tests/ui/ffi_pure.rs b/tests/ui/ffi-attrs/ffi_pure.rs
similarity index 100%
rename from tests/ui/ffi_pure.rs
rename to tests/ui/ffi-attrs/ffi_pure.rs
diff --git a/tests/ui/ffi_pure.stderr b/tests/ui/ffi-attrs/ffi_pure.stderr
similarity index 100%
rename from tests/ui/ffi_pure.stderr
rename to tests/ui/ffi-attrs/ffi_pure.stderr
diff --git a/tests/ui/main-wrong-location.rs b/tests/ui/fn-main/wrong-location.rs
similarity index 100%
rename from tests/ui/main-wrong-location.rs
rename to tests/ui/fn-main/wrong-location.rs
diff --git a/tests/ui/main-wrong-location.stderr b/tests/ui/fn-main/wrong-location.stderr
similarity index 69%
rename from tests/ui/main-wrong-location.stderr
rename to tests/ui/fn-main/wrong-location.stderr
index 9486a94..c47092b 100644
--- a/tests/ui/main-wrong-location.stderr
+++ b/tests/ui/fn-main/wrong-location.stderr
@@ -1,11 +1,11 @@
-error[E0601]: `main` function not found in crate `main_wrong_location`
-  --> $DIR/main-wrong-location.rs:5:2
+error[E0601]: `main` function not found in crate `wrong_location`
+  --> $DIR/wrong-location.rs:5:2
    |
 LL | }
-   |  ^ the main function must be defined at the crate level (in `$DIR/main-wrong-location.rs`)
+   |  ^ the main function must be defined at the crate level (in `$DIR/wrong-location.rs`)
    |
 note: here is a function named `main`
-  --> $DIR/main-wrong-location.rs:4:5
+  --> $DIR/wrong-location.rs:4:5
    |
 LL |     fn main() { }
    |     ^^^^^^^^^
diff --git a/tests/ui/main-wrong-type.rs b/tests/ui/fn-main/wrong-type.rs
similarity index 100%
rename from tests/ui/main-wrong-type.rs
rename to tests/ui/fn-main/wrong-type.rs
diff --git a/tests/ui/main-wrong-type.stderr b/tests/ui/fn-main/wrong-type.stderr
similarity index 90%
rename from tests/ui/main-wrong-type.stderr
rename to tests/ui/fn-main/wrong-type.stderr
index d07fc09..2b00964 100644
--- a/tests/ui/main-wrong-type.stderr
+++ b/tests/ui/fn-main/wrong-type.stderr
@@ -1,5 +1,5 @@
 error[E0580]: `main` function has wrong type
-  --> $DIR/main-wrong-type.rs:6:1
+  --> $DIR/wrong-type.rs:6:1
    |
 LL | fn main(foo: S) {
    | ^^^^^^^^^^^^^^^ incorrect number of function parameters
diff --git a/tests/ui/for/issue-20605.next.stderr b/tests/ui/for/issue-20605.next.stderr
index 6855e17..9860921 100644
--- a/tests/ui/for/issue-20605.next.stderr
+++ b/tests/ui/for/issue-20605.next.stderr
@@ -11,31 +11,13 @@
 LL |     for item in &mut *things { *item = 0 }
    |                 ++++
 
-error: the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
-  --> $DIR/issue-20605.rs:6:17
-   |
-LL |     for item in *things { *item = 0 }
-   |                 ^^^^^^^
-
-error: the type `&mut <dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
-  --> $DIR/issue-20605.rs:6:17
-   |
-LL |     for item in *things { *item = 0 }
-   |                 ^^^^^^^
-
-error: the type `Option<<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item>` is not well-formed
-  --> $DIR/issue-20605.rs:6:17
-   |
-LL |     for item in *things { *item = 0 }
-   |                 ^^^^^^^
-
 error[E0614]: type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::Item` cannot be dereferenced
   --> $DIR/issue-20605.rs:6:27
    |
 LL |     for item in *things { *item = 0 }
    |                           ^^^^^
 
-error: aborting due to 5 previous errors
+error: aborting due to 2 previous errors
 
 Some errors have detailed explanations: E0277, E0614.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/for/issue-20605.rs b/tests/ui/for/issue-20605.rs
index b923a70..647dc84 100644
--- a/tests/ui/for/issue-20605.rs
+++ b/tests/ui/for/issue-20605.rs
@@ -6,9 +6,6 @@
     for item in *things { *item = 0 }
     //[current]~^ ERROR `dyn Iterator<Item = &'a mut u8>` is not an iterator
     //[next]~^^ ERROR `dyn Iterator<Item = &'a mut u8>` is not an iterator
-    //[next]~| ERROR the type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
-    //[next]~| ERROR the type `&mut <dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter` is not well-formed
-    //[next]~| ERROR the type `Option<<<dyn Iterator<Item = &'a mut u8> as IntoIterator>::IntoIter as Iterator>::Item>` is not well-formed
     //[next]~| ERROR type `<dyn Iterator<Item = &'a mut u8> as IntoIterator>::Item` cannot be dereferenced
 
     // FIXME(-Znext-solver): these error messages are horrible and have to be
diff --git a/tests/ui/foreign/foreign-fn-linkname.rs b/tests/ui/foreign/foreign-fn-linkname.rs
index 47edf6f..7ced34e 100644
--- a/tests/ui/foreign/foreign-fn-linkname.rs
+++ b/tests/ui/foreign/foreign-fn-linkname.rs
@@ -1,20 +1,14 @@
 //@ run-pass
 //@ ignore-sgx no libc
 
-// Ensure no false positive on "unused extern crate" lint
-#![deny(unused_extern_crates)]
-
-#![feature(rustc_private)]
-
-extern crate libc;
 use std::ffi::CString;
 
 mod mlibc {
-    use libc::{c_char, size_t};
+    use std::ffi::c_char;
 
     extern "C" {
         #[link_name = "strlen"]
-        pub fn my_strlen(str: *const c_char) -> size_t;
+        pub fn my_strlen(str: *const c_char) -> usize;
     }
 }
 
diff --git a/tests/ui/foreign-fn-return-lifetime.rs b/tests/ui/foreign/foreign-fn-return-lifetime.rs
similarity index 100%
rename from tests/ui/foreign-fn-return-lifetime.rs
rename to tests/ui/foreign/foreign-fn-return-lifetime.rs
diff --git a/tests/ui/foreign-fn-return-lifetime.stderr b/tests/ui/foreign/foreign-fn-return-lifetime.stderr
similarity index 100%
rename from tests/ui/foreign-fn-return-lifetime.stderr
rename to tests/ui/foreign/foreign-fn-return-lifetime.stderr
diff --git a/tests/ui/foreign/foreign2.rs b/tests/ui/foreign/foreign2.rs
index eb24df3..178a042 100644
--- a/tests/ui/foreign/foreign2.rs
+++ b/tests/ui/foreign/foreign2.rs
@@ -1,9 +1,8 @@
 //@ run-pass
-#![allow(dead_code)]
 //@ pretty-expanded FIXME #23616
-#![feature(rustc_private)]
 
-extern crate libc;
+#![allow(dead_code)]
+#![feature(rustc_private)]
 
 mod bar {
     extern "C" {}
@@ -13,14 +12,37 @@
     extern "C" {}
 }
 
+#[cfg(not(windows))]
 mod mlibc {
-    use libc::{c_int, c_void, size_t, ssize_t};
+    extern crate libc;
+    use self::libc::{c_int, c_void, size_t, ssize_t};
 
     extern "C" {
         pub fn write(fd: c_int, buf: *const c_void, count: size_t) -> ssize_t;
     }
 }
 
+#[cfg(windows)]
+mod mlibc {
+    #![allow(non_snake_case)]
+
+    use std::ffi::c_void;
+
+    pub type BOOL = i32;
+    pub type HANDLE = *mut c_void;
+
+    #[link(name = "ntdll")]
+    extern "system" {
+        pub fn WriteFile(
+            hfile: HANDLE,
+            lpbuffer: *const u8,
+            nnumberofbytestowrite: u32,
+            lpnumberofbyteswritten: *mut u32,
+            lpoverlapped: *mut c_void,
+        ) -> BOOL;
+    }
+}
+
 mod baz {
     extern "C" {}
 }
diff --git a/tests/ui/optimization-fuel-0.rs b/tests/ui/fuel/optimization-fuel-0.rs
similarity index 100%
rename from tests/ui/optimization-fuel-0.rs
rename to tests/ui/fuel/optimization-fuel-0.rs
diff --git a/tests/ui/optimization-fuel-0.stderr b/tests/ui/fuel/optimization-fuel-0.stderr
similarity index 100%
rename from tests/ui/optimization-fuel-0.stderr
rename to tests/ui/fuel/optimization-fuel-0.stderr
diff --git a/tests/ui/optimization-fuel-1.rs b/tests/ui/fuel/optimization-fuel-1.rs
similarity index 100%
rename from tests/ui/optimization-fuel-1.rs
rename to tests/ui/fuel/optimization-fuel-1.rs
diff --git a/tests/ui/optimization-fuel-1.stderr b/tests/ui/fuel/optimization-fuel-1.stderr
similarity index 100%
rename from tests/ui/optimization-fuel-1.stderr
rename to tests/ui/fuel/optimization-fuel-1.stderr
diff --git a/tests/ui/print-fuel/print-fuel.rs b/tests/ui/fuel/print-fuel.rs
similarity index 100%
rename from tests/ui/print-fuel/print-fuel.rs
rename to tests/ui/fuel/print-fuel.rs
diff --git a/tests/ui/print-fuel/print-fuel.stderr b/tests/ui/fuel/print-fuel.stderr
similarity index 100%
rename from tests/ui/print-fuel/print-fuel.stderr
rename to tests/ui/fuel/print-fuel.stderr
diff --git a/tests/ui/generic-associated-types/guide-inference-in-gat-arg-deeper.rs b/tests/ui/generic-associated-types/guide-inference-in-gat-arg-deeper.rs
new file mode 100644
index 0000000..96a0f2f
--- /dev/null
+++ b/tests/ui/generic-associated-types/guide-inference-in-gat-arg-deeper.rs
@@ -0,0 +1,19 @@
+// Fix for <https://github.com/rust-lang/rust/issues/125196>.
+//@ check-pass
+
+trait Tr {
+    type Gat<T>;
+}
+
+struct W<T>(T);
+
+fn foo<T: Tr>() where for<'a> &'a T: Tr<Gat<W<i32>> = i32> {
+    let x: <&T as Tr>::Gat<W<_>> = 1i32;
+    // Previously, `match_projection_projections` only checked that
+    // `shallow_resolve(W<?0>) = W<?0>`. This won't prevent *all* inference guidance
+    // from projection predicates in the environment, just ones that guide the
+    // outermost type of each GAT constructor. This is definitely wrong, but there is
+    // code that relies on it in the wild :/
+}
+
+fn main() {}
diff --git a/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.rs b/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.rs
new file mode 100644
index 0000000..b2ac332
--- /dev/null
+++ b/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.rs
@@ -0,0 +1,28 @@
+#![allow(dead_code)]
+
+trait Trait1<T>
+  where T: for<'a> Trait1<T> + 'b { } //~ ERROR use of undeclared lifetime name `'b`
+
+trait Trait2<T>
+where
+    T: B<'b> + for<'a> A<'a>, //~ ERROR use of undeclared lifetime name `'b`
+{
+}
+
+trait Trait3<T>
+where
+    T: B<'b> + for<'a> A<'a> + 'c {}
+    //~^ ERROR use of undeclared lifetime name `'b`
+    //~| ERROR use of undeclared lifetime name `'c`
+
+trait Trait4<T>
+where
+    T: for<'a> A<'a> + 'x + for<'b> B<'b>, //~ ERROR use of undeclared lifetime name `'x`
+{
+}
+
+trait A<'a> {}
+trait B<'a> {}
+
+
+fn main() {}
diff --git a/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.stderr b/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.stderr
new file mode 100644
index 0000000..40f0769
--- /dev/null
+++ b/tests/ui/generics/generic-higher-ranked-lifetime-issue-122714.stderr
@@ -0,0 +1,92 @@
+error[E0261]: use of undeclared lifetime name `'b`
+  --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:4:32
+   |
+LL |   where T: for<'a> Trait1<T> + 'b { }
+   |                                ^^ undeclared lifetime
+   |
+   = note: for more information on higher-ranked polymorphism, visit https://doc.rust-lang.org/nomicon/hrtb.html
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL -   where T: for<'a> Trait1<T> + 'b { }
+LL +   where for<'b, 'a> T: Trait1<T> + 'b { }
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | trait Trait1<'b, T>
+   |              +++
+
+error[E0261]: use of undeclared lifetime name `'b`
+  --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:8:10
+   |
+LL |     T: B<'b> + for<'a> A<'a>,
+   |          ^^ undeclared lifetime
+   |
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL |     T: for<'b> B<'b> + for<'a> A<'a>,
+   |        +++++++
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL -     T: B<'b> + for<'a> A<'a>,
+LL +     for<'b, 'a> T: B<'b> + A<'a>,
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | trait Trait2<'b, T>
+   |              +++
+
+error[E0261]: use of undeclared lifetime name `'b`
+  --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:14:10
+   |
+LL |     T: B<'b> + for<'a> A<'a> + 'c {}
+   |          ^^ undeclared lifetime
+   |
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL |     T: for<'b> B<'b> + for<'a> A<'a> + 'c {}
+   |        +++++++
+help: consider making the bound lifetime-generic with a new `'b` lifetime
+   |
+LL -     T: B<'b> + for<'a> A<'a> + 'c {}
+LL +     for<'b, 'a> T: B<'b> + A<'a> + 'c {}
+   |
+help: consider introducing lifetime `'b` here
+   |
+LL | trait Trait3<'b, T>
+   |              +++
+
+error[E0261]: use of undeclared lifetime name `'c`
+  --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:14:32
+   |
+LL |     T: B<'b> + for<'a> A<'a> + 'c {}
+   |                                ^^ undeclared lifetime
+   |
+help: consider making the bound lifetime-generic with a new `'c` lifetime
+   |
+LL -     T: B<'b> + for<'a> A<'a> + 'c {}
+LL +     for<'c, 'a> T: B<'b> + A<'a> + 'c {}
+   |
+help: consider introducing lifetime `'c` here
+   |
+LL | trait Trait3<'c, T>
+   |              +++
+
+error[E0261]: use of undeclared lifetime name `'x`
+  --> $DIR/generic-higher-ranked-lifetime-issue-122714.rs:20:24
+   |
+LL |     T: for<'a> A<'a> + 'x + for<'b> B<'b>,
+   |                        ^^ undeclared lifetime
+   |
+help: consider making the bound lifetime-generic with a new `'x` lifetime
+   |
+LL -     T: for<'a> A<'a> + 'x + for<'b> B<'b>,
+LL +     for<'x, 'a, 'b> T: A<'a> + 'x + B<'b>,
+   |
+help: consider introducing lifetime `'x` here
+   |
+LL | trait Trait4<'x, T>
+   |              +++
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0261`.
diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs
index 2f53bd0..e0d2e44 100644
--- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs
+++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs
@@ -49,7 +49,7 @@
     // Trying to normalize the type `for<'a> fn(<T as Trait<'a>>::Assoc)`
     // only gets to `<T as Trait<'a>>::Assoc` once `'a` has been already
     // instantiated, causing us to prefer the where-bound over the impl
-    // resulting in a placeholder error. Even if were were to also use the
+    // resulting in a placeholder error. Even if we were to also use the
     // leak check during candidate selection for normalization, this
     // case would still not compile.
     let _higher_ranked_norm: for<'a> fn(<T as Trait<'a>>::Assoc) = |_| ();
diff --git a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr
index f8bed86..a26c617 100644
--- a/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr
+++ b/tests/ui/higher-ranked/trait-bounds/issue-59311.stderr
@@ -1,19 +1,33 @@
 error: implementation of `Trait` is not general enough
   --> $DIR/issue-59311.rs:17:5
    |
-LL |     v.t(|| {});
-   |     ^^^^^^^^^^ implementation of `Trait` is not general enough
+LL | / pub fn crash<V>(v: &V)
+LL | | where
+LL | |     for<'a> &'a V: Trait + 'static,
+   | |____________________-----__________- due to a where-clause on `crash`...
+   |                      |
+   |                      doesn't satisfy where-clause
+LL |   {
+LL |       v.t(|| {});
+   |       ^^^^^^^^^^
    |
-   = note: `Trait` would have to be implemented for the type `&'a V`
+   = note: ...`Trait` would have to be implemented for the type `&'a V`
    = note: ...but `Trait` is actually implemented for the type `&'0 V`, for some specific lifetime `'0`
 
 error: implementation of `Trait` is not general enough
   --> $DIR/issue-59311.rs:17:5
    |
-LL |     v.t(|| {});
-   |     ^^^^^^^^^^ implementation of `Trait` is not general enough
+LL | / pub fn crash<V>(v: &V)
+LL | | where
+LL | |     for<'a> &'a V: Trait + 'static,
+   | |____________________-----__________- due to a where-clause on `crash`...
+   |                      |
+   |                      doesn't satisfy where-clause
+LL |   {
+LL |       v.t(|| {});
+   |       ^^^^^^^^^^
    |
-   = note: `Trait` would have to be implemented for the type `&'a V`
+   = note: ...`Trait` would have to be implemented for the type `&'a V`
    = note: ...but `Trait` is actually implemented for the type `&'0 V`, for some specific lifetime `'0`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
diff --git a/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.rs b/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.rs
new file mode 100644
index 0000000..fa76686
--- /dev/null
+++ b/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.rs
@@ -0,0 +1,11 @@
+// Minimized test from #59311.
+
+pub fn crash()
+where
+    for<'a> &'a (): 'static,
+{
+    || {};
+    //~^ ERROR higher-ranked lifetime error
+}
+
+fn main() {}
diff --git a/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr b/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr
new file mode 100644
index 0000000..9e0d7e4
--- /dev/null
+++ b/tests/ui/higher-ranked/trait-bounds/trivial-does-not-hold.stderr
@@ -0,0 +1,10 @@
+error: higher-ranked lifetime error
+  --> $DIR/trivial-does-not-hold.rs:7:5
+   |
+LL |     || {};
+   |     ^^^^^
+   |
+   = note: could not prove `for<'a> &'a (): 'b`
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs
index 3659551..5a6bf9b 100644
--- a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs
+++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs
@@ -14,6 +14,6 @@
 // `usize: Foo` doesn't hold. Therefore we ICE, because we don't expect to still
 // encounter weak types in `assemble_alias_bound_candidates_recur`.
 fn hello(_: W<A<usize>>) {}
-//~^ ERROR the type `W<A<usize>>` is not well-formed
+//~^ ERROR the size for values of type `A<usize>` cannot be known at compilation time
 
 fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
index 5df27ac..9663fab 100644
--- a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
+++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
@@ -7,11 +7,14 @@
    = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: the type `W<A<usize>>` is not well-formed
+error[E0277]: the size for values of type `A<usize>` cannot be known at compilation time
   --> $DIR/alias-bounds-when-not-wf.rs:16:13
    |
 LL | fn hello(_: W<A<usize>>) {}
-   |             ^^^^^^^^^^^
+   |             ^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `A<usize>`
 
 error: aborting due to 1 previous error; 1 warning emitted
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/impl-trait/issue-99914.stderr b/tests/ui/impl-trait/issue-99914.stderr
index 06e85e5..8adb211 100644
--- a/tests/ui/impl-trait/issue-99914.stderr
+++ b/tests/ui/impl-trait/issue-99914.stderr
@@ -2,7 +2,9 @@
   --> $DIR/issue-99914.rs:9:27
    |
 LL |     t.and_then(|t| -> _ { bar(t) });
-   |                           ^^^^^^ expected `Result<_, Error>`, found future
+   |                       -   ^^^^^^ expected `Result<_, Error>`, found future
+   |                       |
+   |                       expected `Result<_, Error>` because of return type
    |
 help: try wrapping the expression in `Ok`
    |
diff --git a/tests/ui/impl-trait/precise-capturing/apit.stderr b/tests/ui/impl-trait/precise-capturing/apit.stderr
index 36bf80d..96548f5 100644
--- a/tests/ui/impl-trait/precise-capturing/apit.stderr
+++ b/tests/ui/impl-trait/precise-capturing/apit.stderr
@@ -11,7 +11,7 @@
   --> $DIR/apit.rs:4:18
    |
 LL | fn hello(_: impl use<> Sized) {}
-   |                  ^^^
+   |                  ^^^^^
 
 error: aborting due to 1 previous error; 1 warning emitted
 
diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed
new file mode 100644
index 0000000..014ab23
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.fixed
@@ -0,0 +1,29 @@
+//@ run-rustfix
+
+#![feature(precise_capturing)]
+#![allow(unused, incomplete_features)]
+#![deny(impl_trait_overcaptures)]
+
+fn named<'a>(x: &'a i32) -> impl use<> Sized { *x }
+//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+
+fn implicit(x: &i32) -> impl use<> Sized { *x }
+//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+
+struct W;
+impl W {
+    fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self }
+    //~^ ERROR `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
+}
+
+trait Higher<'a> {
+    type Output;
+}
+impl Higher<'_> for () {
+    type Output = ();
+}
+
+fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {}
+//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+
+fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs
new file mode 100644
index 0000000..e4b7828
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.rs
@@ -0,0 +1,29 @@
+//@ run-rustfix
+
+#![feature(precise_capturing)]
+#![allow(unused, incomplete_features)]
+#![deny(impl_trait_overcaptures)]
+
+fn named<'a>(x: &'a i32) -> impl Sized { *x }
+//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+
+fn implicit(x: &i32) -> impl Sized { *x }
+//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+
+struct W;
+impl W {
+    fn hello(&self, x: &i32) -> impl Sized + '_ { self }
+    //~^ ERROR `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
+}
+
+trait Higher<'a> {
+    type Output;
+}
+impl Higher<'_> for () {
+    type Output = ();
+}
+
+fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
+//~^ ERROR `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+
+fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr
new file mode 100644
index 0000000..16cb8b7
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/overcaptures-2024.stderr
@@ -0,0 +1,75 @@
+error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+  --> $DIR/overcaptures-2024.rs:7:29
+   |
+LL | fn named<'a>(x: &'a i32) -> impl Sized { *x }
+   |                             ^^^^^^^^^^
+   |
+note: specifically, this lifetime is in scope but not mentioned in the type's bounds
+  --> $DIR/overcaptures-2024.rs:7:10
+   |
+LL | fn named<'a>(x: &'a i32) -> impl Sized { *x }
+   |          ^^
+   = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
+note: the lint level is defined here
+  --> $DIR/overcaptures-2024.rs:5:9
+   |
+LL | #![deny(impl_trait_overcaptures)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^
+help: use the precise capturing `use<...>` syntax to make the captures explicit
+   |
+LL | fn named<'a>(x: &'a i32) -> impl use<> Sized { *x }
+   |                                  +++++
+
+error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+  --> $DIR/overcaptures-2024.rs:10:25
+   |
+LL | fn implicit(x: &i32) -> impl Sized { *x }
+   |                         ^^^^^^^^^^
+   |
+note: specifically, this lifetime is in scope but not mentioned in the type's bounds
+  --> $DIR/overcaptures-2024.rs:10:16
+   |
+LL | fn implicit(x: &i32) -> impl Sized { *x }
+   |                ^
+   = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
+help: use the precise capturing `use<...>` syntax to make the captures explicit
+   |
+LL | fn implicit(x: &i32) -> impl use<> Sized { *x }
+   |                              +++++
+
+error: `impl Sized + '_` will capture more lifetimes than possibly intended in edition 2024
+  --> $DIR/overcaptures-2024.rs:15:33
+   |
+LL |     fn hello(&self, x: &i32) -> impl Sized + '_ { self }
+   |                                 ^^^^^^^^^^^^^^^
+   |
+note: specifically, this lifetime is in scope but not mentioned in the type's bounds
+  --> $DIR/overcaptures-2024.rs:15:24
+   |
+LL |     fn hello(&self, x: &i32) -> impl Sized + '_ { self }
+   |                        ^
+   = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
+help: use the precise capturing `use<...>` syntax to make the captures explicit
+   |
+LL |     fn hello(&self, x: &i32) -> impl use<'_> Sized + '_ { self }
+   |                                      +++++++
+
+error: `impl Sized` will capture more lifetimes than possibly intended in edition 2024
+  --> $DIR/overcaptures-2024.rs:26:47
+   |
+LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
+   |                                               ^^^^^^^^^^
+   |
+note: specifically, this lifetime is in scope but not mentioned in the type's bounds
+  --> $DIR/overcaptures-2024.rs:26:23
+   |
+LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl Sized> {}
+   |                       ^^
+   = note: all lifetimes in scope will be captured by `impl Trait`s in edition 2024
+help: use the precise capturing `use<...>` syntax to make the captures explicit
+   |
+LL | fn hrtb() -> impl for<'a> Higher<'a, Output = impl use<> Sized> {}
+   |                                                    +++++
+
+error: aborting due to 4 previous errors
+
diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rs b/tests/ui/impl-trait/precise-capturing/redundant.rs
new file mode 100644
index 0000000..108a4cb
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/redundant.rs
@@ -0,0 +1,25 @@
+//@ compile-flags: -Zunstable-options --edition=2024
+//@ check-pass
+
+#![feature(precise_capturing)]
+//~^ WARN the feature `precise_capturing` is incomplete
+
+fn hello<'a>() -> impl use<'a> Sized {}
+//~^ WARN all possible in-scope parameters are already captured
+
+struct Inherent;
+impl Inherent {
+    fn inherent(&self) -> impl use<'_> Sized {}
+    //~^ WARN all possible in-scope parameters are already captured
+}
+
+trait Test<'a> {
+    fn in_trait() -> impl use<'a, Self> Sized;
+    //~^ WARN all possible in-scope parameters are already captured
+}
+impl<'a> Test<'a> for () {
+    fn in_trait() -> impl use<'a> Sized {}
+    //~^ WARN all possible in-scope parameters are already captured
+}
+
+fn main() {}
diff --git a/tests/ui/impl-trait/precise-capturing/redundant.stderr b/tests/ui/impl-trait/precise-capturing/redundant.stderr
new file mode 100644
index 0000000..325f04d
--- /dev/null
+++ b/tests/ui/impl-trait/precise-capturing/redundant.stderr
@@ -0,0 +1,45 @@
+warning: the feature `precise_capturing` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/redundant.rs:4:12
+   |
+LL | #![feature(precise_capturing)]
+   |            ^^^^^^^^^^^^^^^^^
+   |
+   = note: see issue #123432 <https://github.com/rust-lang/rust/issues/123432> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
+  --> $DIR/redundant.rs:7:19
+   |
+LL | fn hello<'a>() -> impl use<'a> Sized {}
+   |                   ^^^^^-------^^^^^^
+   |                        |
+   |                        help: remove the `use<...>` syntax
+   |
+   = note: `#[warn(impl_trait_redundant_captures)]` on by default
+
+warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
+  --> $DIR/redundant.rs:12:27
+   |
+LL |     fn inherent(&self) -> impl use<'_> Sized {}
+   |                           ^^^^^-------^^^^^^
+   |                                |
+   |                                help: remove the `use<...>` syntax
+
+warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
+  --> $DIR/redundant.rs:17:22
+   |
+LL |     fn in_trait() -> impl use<'a, Self> Sized;
+   |                      ^^^^^-------------^^^^^^
+   |                           |
+   |                           help: remove the `use<...>` syntax
+
+warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant
+  --> $DIR/redundant.rs:21:22
+   |
+LL |     fn in_trait() -> impl use<'a> Sized {}
+   |                      ^^^^^-------^^^^^^
+   |                           |
+   |                           help: remove the `use<...>` syntax
+
+warning: 5 warnings emitted
+
diff --git a/tests/ui/imports/issue-37887.rs b/tests/ui/imports/issue-37887.rs
index 58f0c6b..919f46d 100644
--- a/tests/ui/imports/issue-37887.rs
+++ b/tests/ui/imports/issue-37887.rs
@@ -1,4 +1,4 @@
 fn main() {
-    extern crate libc; //~ ERROR use of unstable
-    use libc::*; //~ ERROR unresolved import
+    extern crate test; //~ ERROR use of unstable
+    use test::*; //~ ERROR unresolved import
 }
diff --git a/tests/ui/imports/issue-37887.stderr b/tests/ui/imports/issue-37887.stderr
index 6117fd2..e7792ac 100644
--- a/tests/ui/imports/issue-37887.stderr
+++ b/tests/ui/imports/issue-37887.stderr
@@ -1,19 +1,19 @@
-error[E0432]: unresolved import `libc`
+error[E0432]: unresolved import `test`
   --> $DIR/issue-37887.rs:3:9
    |
-LL |     use libc::*;
-   |         ^^^^ maybe a missing crate `libc`?
+LL |     use test::*;
+   |         ^^^^ maybe a missing crate `test`?
    |
-   = help: consider adding `extern crate libc` to use the `libc` crate
+   = help: consider adding `extern crate test` to use the `test` crate
 
-error[E0658]: use of unstable library feature 'rustc_private': this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via `Cargo.toml` instead?
+error[E0658]: use of unstable library feature 'test'
   --> $DIR/issue-37887.rs:2:5
    |
-LL |     extern crate libc;
+LL |     extern crate test;
    |     ^^^^^^^^^^^^^^^^^^
    |
-   = note: see issue #27812 <https://github.com/rust-lang/rust/issues/27812> for more information
-   = help: add `#![feature(rustc_private)]` to the crate attributes to enable
+   = note: see issue #50297 <https://github.com/rust-lang/rust/issues/50297> for more information
+   = help: add `#![feature(test)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error: aborting due to 2 previous errors
diff --git a/tests/ui/infer-fn-tail-expr.rs b/tests/ui/inference/infer-fn-tail-expr.rs
similarity index 100%
rename from tests/ui/infer-fn-tail-expr.rs
rename to tests/ui/inference/infer-fn-tail-expr.rs
diff --git a/tests/ui/lambda-infer-unresolved.rs b/tests/ui/inference/lambda-infer-unresolved.rs
similarity index 100%
rename from tests/ui/lambda-infer-unresolved.rs
rename to tests/ui/inference/lambda-infer-unresolved.rs
diff --git a/tests/ui/order-dependent-cast-inference.rs b/tests/ui/inference/order-dependent-cast-inference.rs
similarity index 100%
rename from tests/ui/order-dependent-cast-inference.rs
rename to tests/ui/inference/order-dependent-cast-inference.rs
diff --git a/tests/ui/order-dependent-cast-inference.stderr b/tests/ui/inference/order-dependent-cast-inference.stderr
similarity index 100%
rename from tests/ui/order-dependent-cast-inference.stderr
rename to tests/ui/inference/order-dependent-cast-inference.stderr
diff --git a/tests/ui/instrument-coverage/coverage-options.rs b/tests/ui/instrument-coverage/coverage-options.rs
index 332da32..2a80ce4 100644
--- a/tests/ui/instrument-coverage/coverage-options.rs
+++ b/tests/ui/instrument-coverage/coverage-options.rs
@@ -1,5 +1,5 @@
 //@ needs-profiler-support
-//@ revisions: block branch bad
+//@ revisions: block branch mcdc bad
 //@ compile-flags -Cinstrument-coverage
 
 //@ [block] check-pass
diff --git a/tests/ui/intrinsics-always-extern.rs b/tests/ui/intrinsics/always-extern.rs
similarity index 100%
rename from tests/ui/intrinsics-always-extern.rs
rename to tests/ui/intrinsics/always-extern.rs
diff --git a/tests/ui/intrinsics-always-extern.stderr b/tests/ui/intrinsics/always-extern.stderr
similarity index 83%
rename from tests/ui/intrinsics-always-extern.stderr
rename to tests/ui/intrinsics/always-extern.stderr
index 1f7bb5a..44b889c 100644
--- a/tests/ui/intrinsics-always-extern.stderr
+++ b/tests/ui/intrinsics/always-extern.stderr
@@ -1,11 +1,11 @@
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/intrinsics-always-extern.rs:4:32
+  --> $DIR/always-extern.rs:4:32
    |
 LL |     extern "rust-intrinsic" fn foo(&self);
    |                                ^^^
 
 error[E0093]: unrecognized intrinsic function: `hello`
-  --> $DIR/intrinsics-always-extern.rs:12:28
+  --> $DIR/always-extern.rs:12:28
    |
 LL | extern "rust-intrinsic" fn hello() {
    |                            ^^^^^ unrecognized intrinsic
@@ -13,7 +13,7 @@
    = help: if you're adding an intrinsic, be sure to update `check_intrinsic_type`
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/intrinsics-always-extern.rs:8:43
+  --> $DIR/always-extern.rs:8:43
    |
 LL |       extern "rust-intrinsic" fn foo(&self) {
    |  ___________________________________________^
@@ -21,7 +21,7 @@
    | |_____^
 
 error: intrinsic must be in `extern "rust-intrinsic" { ... }` block
-  --> $DIR/intrinsics-always-extern.rs:12:36
+  --> $DIR/always-extern.rs:12:36
    |
 LL |   extern "rust-intrinsic" fn hello() {
    |  ____________________________________^
diff --git a/tests/ui/reify-intrinsic.rs b/tests/ui/intrinsics/reify-intrinsic.rs
similarity index 100%
rename from tests/ui/reify-intrinsic.rs
rename to tests/ui/intrinsics/reify-intrinsic.rs
diff --git a/tests/ui/reify-intrinsic.stderr b/tests/ui/intrinsics/reify-intrinsic.stderr
similarity index 100%
rename from tests/ui/reify-intrinsic.stderr
rename to tests/ui/intrinsics/reify-intrinsic.stderr
diff --git a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr
index 2e0812d..d73d5ba 100644
--- a/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr
+++ b/tests/ui/intrinsics/safe-intrinsic-mismatch.stderr
@@ -22,7 +22,7 @@
   --> $DIR/safe-intrinsic-mismatch.rs:11:16
    |
 LL | const fn assume(_b: bool) {}
-   |                ^ expected unsafe fn, found normal fn
+   |                ^ expected unsafe fn, found safe fn
    |
    = note: expected signature `unsafe fn(_)`
               found signature `fn(_)`
@@ -37,7 +37,7 @@
   --> $DIR/safe-intrinsic-mismatch.rs:15:26
    |
 LL | const fn const_deallocate(_ptr: *mut u8, _size: usize, _align: usize) {}
-   |                          ^ expected unsafe fn, found normal fn
+   |                          ^ expected unsafe fn, found safe fn
    |
    = note: expected signature `unsafe fn(_, _, _)`
               found signature `fn(_, _, _)`
diff --git a/tests/ui/iterators/into-iter-on-arrays-2018.stderr b/tests/ui/iterators/into-iter-on-arrays-2018.stderr
index 2378476..9d6bbf0 100644
--- a/tests/ui/iterators/into-iter-on-arrays-2018.stderr
+++ b/tests/ui/iterators/into-iter-on-arrays-2018.stderr
@@ -1,4 +1,4 @@
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-2018.rs:14:34
    |
 LL |     let _: Iter<'_, i32> = array.into_iter();
@@ -16,7 +16,7 @@
 LL |     let _: Iter<'_, i32> = IntoIterator::into_iter(array);
    |                            ++++++++++++++++++++++++     ~
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-2018.rs:18:44
    |
 LL |     let _: Iter<'_, i32> = Box::new(array).into_iter();
@@ -25,7 +25,7 @@
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-2018.rs:22:43
    |
 LL |     let _: Iter<'_, i32> = Rc::new(array).into_iter();
@@ -34,7 +34,7 @@
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-2018.rs:25:41
    |
 LL |     let _: Iter<'_, i32> = Array(array).into_iter();
@@ -43,7 +43,7 @@
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-2018.rs:32:24
    |
 LL |     for _ in [1, 2, 3].into_iter() {}
diff --git a/tests/ui/iterators/into-iter-on-arrays-lint.stderr b/tests/ui/iterators/into-iter-on-arrays-lint.stderr
index 2fde276..da388d6 100644
--- a/tests/ui/iterators/into-iter-on-arrays-lint.stderr
+++ b/tests/ui/iterators/into-iter-on-arrays-lint.stderr
@@ -1,4 +1,4 @@
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:11:11
    |
 LL |     small.into_iter();
@@ -16,7 +16,7 @@
 LL |     IntoIterator::into_iter(small);
    |     ++++++++++++++++++++++++     ~
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:14:12
    |
 LL |     [1, 2].into_iter();
@@ -33,7 +33,7 @@
 LL |     IntoIterator::into_iter([1, 2]);
    |     ++++++++++++++++++++++++      ~
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:17:9
    |
 LL |     big.into_iter();
@@ -50,7 +50,7 @@
 LL |     IntoIterator::into_iter(big);
    |     ++++++++++++++++++++++++   ~
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:20:15
    |
 LL |     [0u8; 33].into_iter();
@@ -67,7 +67,7 @@
 LL |     IntoIterator::into_iter([0u8; 33]);
    |     ++++++++++++++++++++++++         ~
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:24:21
    |
 LL |     Box::new(small).into_iter();
@@ -76,7 +76,7 @@
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:27:22
    |
 LL |     Box::new([1, 2]).into_iter();
@@ -85,7 +85,7 @@
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:30:19
    |
 LL |     Box::new(big).into_iter();
@@ -94,7 +94,7 @@
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:33:25
    |
 LL |     Box::new([0u8; 33]).into_iter();
@@ -103,7 +103,7 @@
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:37:31
    |
 LL |     Box::new(Box::new(small)).into_iter();
@@ -112,7 +112,7 @@
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:40:32
    |
 LL |     Box::new(Box::new([1, 2])).into_iter();
@@ -121,7 +121,7 @@
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:43:29
    |
 LL |     Box::new(Box::new(big)).into_iter();
@@ -130,7 +130,7 @@
    = warning: this changes meaning in Rust 2021
    = note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/IntoIterator-for-arrays.html>
 
-warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to <[T; N] as IntoIterator>::into_iter in Rust 2021
+warning: this method call resolves to `<&[T; N] as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<[T; N] as IntoIterator>::into_iter` in Rust 2021
   --> $DIR/into-iter-on-arrays-lint.rs:46:35
    |
 LL |     Box::new(Box::new([0u8; 33])).into_iter();
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-2021.rs b/tests/ui/iterators/into-iter-on-boxed-slices-2021.rs
new file mode 100644
index 0000000..3d9d131
--- /dev/null
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-2021.rs
@@ -0,0 +1,46 @@
+//@ check-pass
+//@ edition:2018
+
+use std::ops::Deref;
+use std::rc::Rc;
+use std::slice::Iter;
+use std::vec::IntoIter;
+
+fn main() {
+    let boxed_slice = vec![0; 10].into_boxed_slice();
+
+    // Before 2024, the method dispatched to `IntoIterator for Box<[T]>`,
+    // which we continue to support for compatibility.
+    let _: Iter<'_, i32> = boxed_slice.into_iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+
+    let _: Iter<'_, i32> = Box::new(boxed_slice.clone()).into_iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+
+    let _: Iter<'_, i32> = Rc::new(boxed_slice.clone()).into_iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+    let _: Iter<'_, i32> = Array(boxed_slice.clone()).into_iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+
+    // But you can always use the trait method explicitly as an boxed_slice.
+    let _: IntoIter<i32> = IntoIterator::into_iter(boxed_slice);
+
+    for _ in (Box::new([1, 2, 3]) as Box<[_]>).into_iter() {}
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+}
+
+/// User type that dereferences to a boxed slice.
+struct Array(Box<[i32]>);
+
+impl Deref for Array {
+    type Target = Box<[i32]>;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr b/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr
new file mode 100644
index 0000000..d7f38a2
--- /dev/null
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-2021.stderr
@@ -0,0 +1,60 @@
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-2021.rs:14:40
+   |
+LL |     let _: Iter<'_, i32> = boxed_slice.into_iter();
+   |                                        ^^^^^^^^^
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: `#[warn(boxed_slice_into_iter)]` on by default
+help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
+   |
+LL |     let _: Iter<'_, i32> = boxed_slice.iter();
+   |                                        ~~~~
+help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
+   |
+LL |     let _: Iter<'_, i32> = IntoIterator::into_iter(boxed_slice);
+   |                            ++++++++++++++++++++++++           ~
+
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-2021.rs:18:58
+   |
+LL |     let _: Iter<'_, i32> = Box::new(boxed_slice.clone()).into_iter();
+   |                                                          ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this changes meaning in Rust 2024
+
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-2021.rs:22:57
+   |
+LL |     let _: Iter<'_, i32> = Rc::new(boxed_slice.clone()).into_iter();
+   |                                                         ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this changes meaning in Rust 2024
+
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-2021.rs:25:55
+   |
+LL |     let _: Iter<'_, i32> = Array(boxed_slice.clone()).into_iter();
+   |                                                       ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this changes meaning in Rust 2024
+
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-2021.rs:32:48
+   |
+LL |     for _ in (Box::new([1, 2, 3]) as Box<[_]>).into_iter() {}
+   |                                                ^^^^^^^^^
+   |
+   = warning: this changes meaning in Rust 2024
+help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
+   |
+LL |     for _ in (Box::new([1, 2, 3]) as Box<[_]>).iter() {}
+   |                                                ~~~~
+help: or remove `.into_iter()` to iterate by value
+   |
+LL -     for _ in (Box::new([1, 2, 3]) as Box<[_]>).into_iter() {}
+LL +     for _ in (Box::new([1, 2, 3]) as Box<[_]>) {}
+   |
+
+warning: 5 warnings emitted
+
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-2024.rs b/tests/ui/iterators/into-iter-on-boxed-slices-2024.rs
new file mode 100644
index 0000000..ffd6f02
--- /dev/null
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-2024.rs
@@ -0,0 +1,20 @@
+//@ check-pass
+//@ edition:2024
+//@ compile-flags: -Zunstable-options
+
+use std::ops::Deref;
+use std::rc::Rc;
+use std::vec::IntoIter;
+
+fn main() {
+    let boxed_slice = vec![0; 10].into_boxed_slice();
+
+    // In 2021, the method dispatches to `IntoIterator for [T; N]`.
+    let _: IntoIter<i32> = boxed_slice.clone().into_iter();
+
+    // And through other boxes.
+    let _: IntoIter<i32> = Box::new(boxed_slice.clone()).into_iter();
+
+    // You can always use the trait method explicitly as a boxed_slice.
+    let _: IntoIter<i32> = IntoIterator::into_iter(boxed_slice.clone());
+}
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-lint.fixed b/tests/ui/iterators/into-iter-on-boxed-slices-lint.fixed
new file mode 100644
index 0000000..265a6c7
--- /dev/null
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-lint.fixed
@@ -0,0 +1,30 @@
+//@ run-pass
+//@ run-rustfix
+//@ rustfix-only-machine-applicable
+
+#[allow(unused_must_use, unused_allocation)]
+fn main() {
+    let boxed = vec![1, 2].into_boxed_slice();
+
+    // Expressions that should trigger the lint
+    boxed.iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+    Box::new(boxed.clone()).iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+    Box::new(Box::new(boxed.clone())).iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+
+    // Expressions that should not
+    (&boxed).into_iter();
+
+    for _ in &boxed {}
+    (&boxed as &[_]).into_iter();
+    boxed[..].into_iter();
+    std::iter::IntoIterator::into_iter(&boxed);
+
+    #[allow(boxed_slice_into_iter)]
+    boxed.into_iter();
+}
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-lint.rs b/tests/ui/iterators/into-iter-on-boxed-slices-lint.rs
new file mode 100644
index 0000000..dd78e48
--- /dev/null
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-lint.rs
@@ -0,0 +1,30 @@
+//@ run-pass
+//@ run-rustfix
+//@ rustfix-only-machine-applicable
+
+#[allow(unused_must_use, unused_allocation)]
+fn main() {
+    let boxed = vec![1, 2].into_boxed_slice();
+
+    // Expressions that should trigger the lint
+    boxed.into_iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+    Box::new(boxed.clone()).into_iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+    Box::new(Box::new(boxed.clone())).into_iter();
+    //~^ WARNING this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter`
+    //~| WARNING this changes meaning
+
+    // Expressions that should not
+    (&boxed).into_iter();
+
+    for _ in &boxed {}
+    (&boxed as &[_]).into_iter();
+    boxed[..].into_iter();
+    std::iter::IntoIterator::into_iter(&boxed);
+
+    #[allow(boxed_slice_into_iter)]
+    boxed.into_iter();
+}
diff --git a/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr b/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr
new file mode 100644
index 0000000..b73faf0
--- /dev/null
+++ b/tests/ui/iterators/into-iter-on-boxed-slices-lint.stderr
@@ -0,0 +1,35 @@
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-lint.rs:10:11
+   |
+LL |     boxed.into_iter();
+   |           ^^^^^^^^^
+   |
+   = warning: this changes meaning in Rust 2024
+   = note: `#[warn(boxed_slice_into_iter)]` on by default
+help: use `.iter()` instead of `.into_iter()` to avoid ambiguity
+   |
+LL |     boxed.iter();
+   |           ~~~~
+help: or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
+   |
+LL |     IntoIterator::into_iter(boxed);
+   |     ++++++++++++++++++++++++     ~
+
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-lint.rs:13:29
+   |
+LL |     Box::new(boxed.clone()).into_iter();
+   |                             ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this changes meaning in Rust 2024
+
+warning: this method call resolves to `<&Box<[T]> as IntoIterator>::into_iter` (due to backwards compatibility), but will resolve to `<Box<[T]> as IntoIterator>::into_iter` in Rust 2024
+  --> $DIR/into-iter-on-boxed-slices-lint.rs:16:39
+   |
+LL |     Box::new(Box::new(boxed.clone())).into_iter();
+   |                                       ^^^^^^^^^ help: use `.iter()` instead of `.into_iter()` to avoid ambiguity: `iter`
+   |
+   = warning: this changes meaning in Rust 2024
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/lifetimes/issue-17728.stderr b/tests/ui/lifetimes/issue-17728.stderr
index 23547f7..eb4381e 100644
--- a/tests/ui/lifetimes/issue-17728.stderr
+++ b/tests/ui/lifetimes/issue-17728.stderr
@@ -29,8 +29,8 @@
    |
 help: consider introducing a named lifetime parameter
    |
-LL |     fn attemptTraverse<'a>(&'a self, room: &'a Room, directionStr: &str) -> Result<&Room, &str> {
-   |                       ++++  ++              ++
+LL |     fn attemptTraverse<'a>(&self, room: &'a Room, directionStr: &str) -> Result<&'a Room, &'a str> {
+   |                       ++++               ++                                      ++        ++
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/lifetimes/issue-90170-elision-mismatch.stderr b/tests/ui/lifetimes/issue-90170-elision-mismatch.stderr
index 48fb3fb..82511d0 100644
--- a/tests/ui/lifetimes/issue-90170-elision-mismatch.stderr
+++ b/tests/ui/lifetimes/issue-90170-elision-mismatch.stderr
@@ -35,7 +35,7 @@
    |                                               |        let's call the lifetime of this reference `'1`
    |                                               let's call the lifetime of this reference `'2`
    |
-help: consider introducing a named lifetime parameter
+help: consider reusing a named lifetime parameter
    |
 LL | pub fn foo3<'a>(_other: &'a [u8], x: &mut Vec<&'a u8>, y: &'a u8) { x.push(y); }
    |                                                ++          ++
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr
index 5827b2f..2caab3d 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-if-else-using-impl.stderr
@@ -8,6 +8,11 @@
 LL |
 LL |         if x > y { x } else { y }
    |                    ^ associated function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+   |
+help: consider reusing a named lifetime parameter and update trait if needed
+   |
+LL |     fn foo<'a>(x: &'a i32, y: &'a i32) -> &'a i32 {
+   |                    ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.fixed b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.fixed
new file mode 100644
index 0000000..40eee22
--- /dev/null
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.fixed
@@ -0,0 +1,14 @@
+//@ run-rustfix
+#![allow(dead_code)]
+struct Foo {
+    field: i32,
+}
+
+impl Foo {
+    fn foo<'a>(&self, x: &'a i32) -> &'a i32 {
+        x
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs
index 49993ac..c8dd958 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.rs
@@ -1,15 +1,14 @@
+//@ run-rustfix
+#![allow(dead_code)]
 struct Foo {
-  field: i32
+    field: i32,
 }
 
 impl Foo {
-  fn foo<'a>(&self, x: &'a i32) -> &i32 {
-
-    x
-    //~^ ERROR lifetime may not live long enough
-
-  }
-
+    fn foo<'a>(&self, x: &'a i32) -> &i32 {
+        x
+        //~^ ERROR lifetime may not live long enough
+    }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr
index da454b8..c743351 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-return-type-is-anon.stderr
@@ -1,13 +1,17 @@
 error: lifetime may not live long enough
-  --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:8:5
+  --> $DIR/ex1-return-one-existing-name-return-type-is-anon.rs:9:9
    |
-LL |   fn foo<'a>(&self, x: &'a i32) -> &i32 {
-   |          --  - let's call the lifetime of this reference `'1`
-   |          |
-   |          lifetime `'a` defined here
-LL |
-LL |     x
-   |     ^ method was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
+LL |     fn foo<'a>(&self, x: &'a i32) -> &i32 {
+   |            --  - let's call the lifetime of this reference `'1`
+   |            |
+   |            lifetime `'a` defined here
+LL |         x
+   |         ^ method was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
+   |
+help: consider reusing a named lifetime parameter and update trait if needed
+   |
+LL |     fn foo<'a>(&self, x: &'a i32) -> &'a i32 {
+   |                                       ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr
index a1dfff88..4ed6c3b 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex1-return-one-existing-name-self-is-anon.stderr
@@ -8,6 +8,11 @@
 LL |
 LL |         if true { x } else { self }
    |                              ^^^^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'1`
+   |
+help: consider reusing a named lifetime parameter and update trait if needed
+   |
+LL |     fn foo<'a>(&'a self, x: &'a Foo) -> &'a Foo {
+   |                 ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr b/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr
index df1d03d..6f7127d 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.stderr
@@ -7,6 +7,11 @@
    |        has type `&mut Vec<Ref<'2, i32>>`
 LL |     x.push(y);
    |     ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(x: &mut Vec<Ref<'a, i32>>, y: Ref<'a, i32>) {
+   |       ++++                 +++               +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr
index 4f1cb1e..f8ad923 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-2.stderr
@@ -7,6 +7,11 @@
    |        has type `Ref<'_, '2>`
 LL |     x.b = y.b;
    |     ^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(mut x: Ref<'a, 'a>, y: Ref<'a, 'a>) {
+   |       ++++           ++++++++        ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr
index 3a19479..a114977 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs-3.stderr
@@ -8,6 +8,11 @@
    |        has type `Ref<'2, '_>`
 LL |     x.a = x.b;
    |     ^^^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(mut x: Ref<'a, 'a>) {
+   |       ++++           ++++++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr
index c778f77..017bfa7 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.stderr
@@ -7,6 +7,11 @@
    |        has type `Vec<Ref<'2>>`
 LL |     x.push(y);
    |     ^^^^^^^^^ argument requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(mut x: Vec<Ref<'a>>, y: Ref<'a>) {
+   |       ++++               ++++         ++++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr
index bbd6290..0980de9 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-2.stderr
@@ -7,6 +7,11 @@
    |        has type `Ref<'_, '1>`
 LL |     y = x.b;
    |     ^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(mut x: Ref<'a, 'a>, y: &'a u32) {
+   |       ++++           ++++++++      ++
 
 error[E0384]: cannot assign to immutable argument `y`
   --> $DIR/ex3-both-anon-regions-one-is-struct-2.rs:4:5
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr
index 60ca416..d9c7530 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-3.stderr
@@ -7,6 +7,11 @@
    |        has type `Ref<'_, '2>`
 LL |     y.b = x;
    |     ^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(mut y: Ref<'a, 'a>, x: &'a u32) {
+   |       ++++           ++++++++      ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr
index 98e490c..d07b821 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct-4.stderr
@@ -7,6 +7,11 @@
    |        has type `Ref<'_, '2>`
 LL |     y.b = x;
    |     ^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(mut y: Ref<'a, 'a>, x: &'a u32) {
+   |       ++++           ++++++++      ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr
index ea1cc1f..ef28dde 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-one-is-struct.stderr
@@ -7,6 +7,11 @@
    |        has type `Ref<'_, '2>`
 LL |     x.b = y;
    |     ^^^^^^^ assignment requires that `'1` must outlive `'2`
+   |
+help: consider introducing a named lifetime parameter
+   |
+LL | fn foo<'a>(mut x: Ref<'a, 'a>, y: &'a u32) {
+   |       ++++           ++++++++      ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.fixed b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.fixed
new file mode 100644
index 0000000..40eee22
--- /dev/null
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.fixed
@@ -0,0 +1,14 @@
+//@ run-rustfix
+#![allow(dead_code)]
+struct Foo {
+    field: i32,
+}
+
+impl Foo {
+    fn foo<'a>(&self, x: &'a i32) -> &'a i32 {
+        x
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs
index 3ffd7be..0225d8c 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.rs
@@ -1,12 +1,14 @@
+//@ run-rustfix
+#![allow(dead_code)]
 struct Foo {
-  field: i32
+    field: i32,
 }
 
 impl Foo {
-  fn foo<'a>(&self, x: &i32) -> &i32 {
-    x
-    //~^ ERROR lifetime may not live long enough
-  }
+    fn foo<'a>(&self, x: &i32) -> &i32 {
+        x
+        //~^ ERROR lifetime may not live long enough
+    }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr
index e934ce7..673a87a 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-return-type-is-anon.stderr
@@ -1,17 +1,17 @@
 error: lifetime may not live long enough
-  --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:7:5
+  --> $DIR/ex3-both-anon-regions-return-type-is-anon.rs:9:9
    |
-LL |   fn foo<'a>(&self, x: &i32) -> &i32 {
-   |              -         - let's call the lifetime of this reference `'1`
-   |              |
-   |              let's call the lifetime of this reference `'2`
-LL |     x
-   |     ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
+LL |     fn foo<'a>(&self, x: &i32) -> &i32 {
+   |                -         - let's call the lifetime of this reference `'1`
+   |                |
+   |                let's call the lifetime of this reference `'2`
+LL |         x
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
    |
-help: consider introducing a named lifetime parameter and update trait if needed
+help: consider reusing a named lifetime parameter and update trait if needed
    |
-LL |   fn foo<'a>(&'a self, x: &'a i32) -> &i32 {
-   |               ++           ++
+LL |     fn foo<'a>(&self, x: &'a i32) -> &'a i32 {
+   |                           ++          ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr
index dde271d..64bd448 100644
--- a/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr
+++ b/tests/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-self-is-anon.stderr
@@ -8,10 +8,10 @@
 LL |         if true { x } else { self }
    |                   ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
    |
-help: consider introducing a named lifetime parameter and update trait if needed
+help: consider reusing a named lifetime parameter and update trait if needed
    |
-LL |     fn foo<'a>(&'a self, x: &'a Foo) -> &Foo {
-   |                 ++           ++
+LL |     fn foo<'a>(&self, x: &'a Foo) -> &'a Foo {
+   |                           ++          ++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/lint/anonymous-reexport.stderr b/tests/ui/lint/anonymous-reexport.stderr
index e3854a5..c4ee18f 100644
--- a/tests/ui/lint/anonymous-reexport.stderr
+++ b/tests/ui/lint/anonymous-reexport.stderr
@@ -34,7 +34,7 @@
 LL | pub use self::my_mod::{Bar as _, Foo as _};
    |                        ^^^^^^^^
 
-error: unused imports: `Bar as _`, `TyBar as _`
+error: unused imports: `Bar as _` and `TyBar as _`
   --> $DIR/anonymous-reexport.rs:17:24
    |
 LL | pub use self::my_mod::{Bar as _, TyBar as _};
diff --git a/tests/ui/lint-group-denied-lint-allowed.rs b/tests/ui/lint/group-denied-lint-allowed.rs
similarity index 100%
rename from tests/ui/lint-group-denied-lint-allowed.rs
rename to tests/ui/lint/group-denied-lint-allowed.rs
diff --git a/tests/ui/lint-group-forbid-always-trumps-cli.rs b/tests/ui/lint/group-forbid-always-trumps-cli.rs
similarity index 100%
rename from tests/ui/lint-group-forbid-always-trumps-cli.rs
rename to tests/ui/lint/group-forbid-always-trumps-cli.rs
diff --git a/tests/ui/lint-group-forbid-always-trumps-cli.stderr b/tests/ui/lint/group-forbid-always-trumps-cli.stderr
similarity index 84%
rename from tests/ui/lint-group-forbid-always-trumps-cli.stderr
rename to tests/ui/lint/group-forbid-always-trumps-cli.stderr
index 04a0f56..21674eb 100644
--- a/tests/ui/lint-group-forbid-always-trumps-cli.stderr
+++ b/tests/ui/lint/group-forbid-always-trumps-cli.stderr
@@ -1,5 +1,5 @@
 error: unused variable: `x`
-  --> $DIR/lint-group-forbid-always-trumps-cli.rs:4:9
+  --> $DIR/group-forbid-always-trumps-cli.rs:4:9
    |
 LL |     let x = 1;
    |         ^ help: if this is intentional, prefix it with an underscore: `_x`
diff --git a/tests/ui/lint/lint-unnecessary-parens.fixed b/tests/ui/lint/lint-unnecessary-parens.fixed
index 973bbd7..760897c 100644
--- a/tests/ui/lint/lint-unnecessary-parens.fixed
+++ b/tests/ui/lint/lint-unnecessary-parens.fixed
@@ -46,6 +46,28 @@
 macro_rules! baz {
     ($($foo:expr),+) => {
         ($($foo),*)
+    };
+}
+
+macro_rules! unit {
+    () => {
+        ()
+    };
+}
+
+struct One;
+
+impl std::ops::Sub<One> for () {
+    type Output = i32;
+    fn sub(self, _: One) -> Self::Output {
+        -1
+    }
+}
+
+impl std::ops::Neg for One {
+    type Output = i32;
+    fn neg(self) -> Self::Output {
+        -1
     }
 }
 
@@ -94,4 +116,13 @@
 
     let _a = baz!(3, 4);
     let _b = baz!(3);
+
+    let _ = {
+        unit!() - One //~ ERROR unnecessary parentheses around block return value
+    } + {
+        unit![] - One //~ ERROR unnecessary parentheses around block return value
+    } + {
+        // FIXME: false positive. This parenthesis is required.
+        unit! {} - One //~ ERROR unnecessary parentheses around block return value
+    };
 }
diff --git a/tests/ui/lint/lint-unnecessary-parens.rs b/tests/ui/lint/lint-unnecessary-parens.rs
index 40cd61f..7cbaac8 100644
--- a/tests/ui/lint/lint-unnecessary-parens.rs
+++ b/tests/ui/lint/lint-unnecessary-parens.rs
@@ -46,6 +46,28 @@
 macro_rules! baz {
     ($($foo:expr),+) => {
         ($($foo),*)
+    };
+}
+
+macro_rules! unit {
+    () => {
+        ()
+    };
+}
+
+struct One;
+
+impl std::ops::Sub<One> for () {
+    type Output = i32;
+    fn sub(self, _: One) -> Self::Output {
+        -1
+    }
+}
+
+impl std::ops::Neg for One {
+    type Output = i32;
+    fn neg(self) -> Self::Output {
+        -1
     }
 }
 
@@ -94,4 +116,13 @@
 
     let _a = baz!(3, 4);
     let _b = baz!(3);
+
+    let _ = {
+        (unit!() - One) //~ ERROR unnecessary parentheses around block return value
+    } + {
+        (unit![] - One) //~ ERROR unnecessary parentheses around block return value
+    } + {
+        // FIXME: false positive. This parenthesis is required.
+        (unit! {} - One) //~ ERROR unnecessary parentheses around block return value
+    };
 }
diff --git a/tests/ui/lint/lint-unnecessary-parens.stderr b/tests/ui/lint/lint-unnecessary-parens.stderr
index ba7a78b..755dd5f 100644
--- a/tests/ui/lint/lint-unnecessary-parens.stderr
+++ b/tests/ui/lint/lint-unnecessary-parens.stderr
@@ -124,7 +124,7 @@
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:52:31
+  --> $DIR/lint-unnecessary-parens.rs:74:31
    |
 LL | pub const CONST_ITEM: usize = (10);
    |                               ^  ^
@@ -136,7 +136,7 @@
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:53:33
+  --> $DIR/lint-unnecessary-parens.rs:75:33
    |
 LL | pub static STATIC_ITEM: usize = (10);
    |                                 ^  ^
@@ -148,7 +148,7 @@
    |
 
 error: unnecessary parentheses around function argument
-  --> $DIR/lint-unnecessary-parens.rs:57:9
+  --> $DIR/lint-unnecessary-parens.rs:79:9
    |
 LL |     bar((true));
    |         ^    ^
@@ -160,7 +160,7 @@
    |
 
 error: unnecessary parentheses around `if` condition
-  --> $DIR/lint-unnecessary-parens.rs:59:8
+  --> $DIR/lint-unnecessary-parens.rs:81:8
    |
 LL |     if (true) {}
    |        ^    ^
@@ -172,7 +172,7 @@
    |
 
 error: unnecessary parentheses around `while` condition
-  --> $DIR/lint-unnecessary-parens.rs:60:11
+  --> $DIR/lint-unnecessary-parens.rs:82:11
    |
 LL |     while (true) {}
    |           ^    ^
@@ -184,7 +184,7 @@
    |
 
 error: unnecessary parentheses around `match` scrutinee expression
-  --> $DIR/lint-unnecessary-parens.rs:61:11
+  --> $DIR/lint-unnecessary-parens.rs:83:11
    |
 LL |     match (true) {
    |           ^    ^
@@ -196,7 +196,7 @@
    |
 
 error: unnecessary parentheses around `let` scrutinee expression
-  --> $DIR/lint-unnecessary-parens.rs:64:16
+  --> $DIR/lint-unnecessary-parens.rs:86:16
    |
 LL |     if let 1 = (1) {}
    |                ^ ^
@@ -208,7 +208,7 @@
    |
 
 error: unnecessary parentheses around `let` scrutinee expression
-  --> $DIR/lint-unnecessary-parens.rs:65:19
+  --> $DIR/lint-unnecessary-parens.rs:87:19
    |
 LL |     while let 1 = (2) {}
    |                   ^ ^
@@ -220,7 +220,7 @@
    |
 
 error: unnecessary parentheses around method argument
-  --> $DIR/lint-unnecessary-parens.rs:81:24
+  --> $DIR/lint-unnecessary-parens.rs:103:24
    |
 LL |     X { y: false }.foo((true));
    |                        ^    ^
@@ -232,7 +232,7 @@
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:83:18
+  --> $DIR/lint-unnecessary-parens.rs:105:18
    |
 LL |     let mut _a = (0);
    |                  ^ ^
@@ -244,7 +244,7 @@
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:84:10
+  --> $DIR/lint-unnecessary-parens.rs:106:10
    |
 LL |     _a = (0);
    |          ^ ^
@@ -256,7 +256,7 @@
    |
 
 error: unnecessary parentheses around assigned value
-  --> $DIR/lint-unnecessary-parens.rs:85:11
+  --> $DIR/lint-unnecessary-parens.rs:107:11
    |
 LL |     _a += (1);
    |           ^ ^
@@ -268,7 +268,7 @@
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:87:8
+  --> $DIR/lint-unnecessary-parens.rs:109:8
    |
 LL |     let(mut _a) = 3;
    |        ^      ^
@@ -280,7 +280,7 @@
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:88:9
+  --> $DIR/lint-unnecessary-parens.rs:110:9
    |
 LL |     let (mut _a) = 3;
    |         ^      ^
@@ -292,7 +292,7 @@
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:89:8
+  --> $DIR/lint-unnecessary-parens.rs:111:8
    |
 LL |     let( mut _a) = 3;
    |        ^^      ^
@@ -304,7 +304,7 @@
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:91:8
+  --> $DIR/lint-unnecessary-parens.rs:113:8
    |
 LL |     let(_a) = 3;
    |        ^  ^
@@ -316,7 +316,7 @@
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:92:9
+  --> $DIR/lint-unnecessary-parens.rs:114:9
    |
 LL |     let (_a) = 3;
    |         ^  ^
@@ -328,7 +328,7 @@
    |
 
 error: unnecessary parentheses around pattern
-  --> $DIR/lint-unnecessary-parens.rs:93:8
+  --> $DIR/lint-unnecessary-parens.rs:115:8
    |
 LL |     let( _a) = 3;
    |        ^^  ^
@@ -339,5 +339,41 @@
 LL +     let _a = 3;
    |
 
-error: aborting due to 28 previous errors
+error: unnecessary parentheses around block return value
+  --> $DIR/lint-unnecessary-parens.rs:121:9
+   |
+LL |         (unit!() - One)
+   |         ^             ^
+   |
+help: remove these parentheses
+   |
+LL -         (unit!() - One)
+LL +         unit!() - One
+   |
+
+error: unnecessary parentheses around block return value
+  --> $DIR/lint-unnecessary-parens.rs:123:9
+   |
+LL |         (unit![] - One)
+   |         ^             ^
+   |
+help: remove these parentheses
+   |
+LL -         (unit![] - One)
+LL +         unit![] - One
+   |
+
+error: unnecessary parentheses around block return value
+  --> $DIR/lint-unnecessary-parens.rs:126:9
+   |
+LL |         (unit! {} - One)
+   |         ^              ^
+   |
+help: remove these parentheses
+   |
+LL -         (unit! {} - One)
+LL +         unit! {} - One
+   |
+
+error: aborting due to 31 previous errors
 
diff --git a/tests/ui/lint/reference_casting.rs b/tests/ui/lint/reference_casting.rs
index d6897ab..87fa42f 100644
--- a/tests/ui/lint/reference_casting.rs
+++ b/tests/ui/lint/reference_casting.rs
@@ -247,6 +247,27 @@
     unsafe fn from_ref(this: &i32) -> &i64 {
         &*(this as *const i32 as *const i64)
     }
+
+    // https://github.com/rust-lang/rust/issues/124685
+    unsafe fn slice_index(array: &mut [u8], offset: usize) {
+        let a1 = &mut array[offset];
+        let a2 = a1 as *mut u8;
+        let a3 = a2 as *mut u64;
+        unsafe { *a3 = 3 };
+    }
+
+    unsafe fn field_access(v: &mut Vec3<i32>) {
+        let r = &mut v.0;
+        let ptr = r as *mut i32 as *mut Vec3<i32>;
+        unsafe { *ptr = Vec3(0, 0, 0) }
+    }
+
+    unsafe fn deref(v: &mut Vec3<i32>) {
+        let r = &mut v.0;
+        let r = &mut *r;
+        let ptr = &mut *(r as *mut i32 as *mut Vec3<i32>);
+        unsafe { *ptr = Vec3(0, 0, 0) }
+    }
 }
 
 const RAW_PTR: *mut u8 = 1 as *mut u8;
diff --git a/tests/ui/lint-unknown-lints-at-crate-level.rs b/tests/ui/lint/unknown-lints-at-crate-level.rs
similarity index 100%
rename from tests/ui/lint-unknown-lints-at-crate-level.rs
rename to tests/ui/lint/unknown-lints-at-crate-level.rs
diff --git a/tests/ui/lint/unnecessary-extern-crate.rs b/tests/ui/lint/unnecessary-extern-crate.rs
index 6ca3b96..7f97a4c 100644
--- a/tests/ui/lint/unnecessary-extern-crate.rs
+++ b/tests/ui/lint/unnecessary-extern-crate.rs
@@ -1,12 +1,12 @@
 //@ edition:2018
 
 #![deny(unused_extern_crates)]
-#![feature(test, rustc_private)]
+#![feature(test)]
 
-extern crate libc;
+extern crate core;
 //~^ ERROR unused extern crate
 //~| HELP remove
-extern crate libc as x;
+extern crate core as x;
 //~^ ERROR unused extern crate
 //~| HELP remove
 
@@ -28,11 +28,11 @@
 
     pub(super) extern crate alloc as d;
 
-    extern crate libc;
+    extern crate core;
     //~^ ERROR unused extern crate
     //~| HELP remove
 
-    extern crate libc as x;
+    extern crate core as x;
     //~^ ERROR unused extern crate
     //~| HELP remove
 
@@ -41,11 +41,11 @@
     pub extern crate test as y;
 
     mod bar {
-        extern crate libc;
+        extern crate core;
         //~^ ERROR unused extern crate
         //~| HELP remove
 
-        extern crate libc as x;
+        extern crate core as x;
         //~^ ERROR unused extern crate
         //~| HELP remove
 
diff --git a/tests/ui/lint/unnecessary-extern-crate.stderr b/tests/ui/lint/unnecessary-extern-crate.stderr
index 14ba9d0..1fa4aa9 100644
--- a/tests/ui/lint/unnecessary-extern-crate.stderr
+++ b/tests/ui/lint/unnecessary-extern-crate.stderr
@@ -1,7 +1,7 @@
 error: unused extern crate
   --> $DIR/unnecessary-extern-crate.rs:6:1
    |
-LL | extern crate libc;
+LL | extern crate core;
    | ^^^^^^^^^^^^^^^^^^ help: remove it
    |
 note: the lint level is defined here
@@ -13,31 +13,31 @@
 error: unused extern crate
   --> $DIR/unnecessary-extern-crate.rs:9:1
    |
-LL | extern crate libc as x;
+LL | extern crate core as x;
    | ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
 
 error: unused extern crate
   --> $DIR/unnecessary-extern-crate.rs:31:5
    |
-LL |     extern crate libc;
+LL |     extern crate core;
    |     ^^^^^^^^^^^^^^^^^^ help: remove it
 
 error: unused extern crate
   --> $DIR/unnecessary-extern-crate.rs:35:5
    |
-LL |     extern crate libc as x;
+LL |     extern crate core as x;
    |     ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
 
 error: unused extern crate
   --> $DIR/unnecessary-extern-crate.rs:44:9
    |
-LL |         extern crate libc;
+LL |         extern crate core;
    |         ^^^^^^^^^^^^^^^^^^ help: remove it
 
 error: unused extern crate
   --> $DIR/unnecessary-extern-crate.rs:48:9
    |
-LL |         extern crate libc as x;
+LL |         extern crate core as x;
    |         ^^^^^^^^^^^^^^^^^^^^^^^ help: remove it
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/lint/unused/import_remove_line.stderr b/tests/ui/lint/unused/import_remove_line.stderr
index 0e8c5de..b2a1666 100644
--- a/tests/ui/lint/unused/import_remove_line.stderr
+++ b/tests/ui/lint/unused/import_remove_line.stderr
@@ -1,4 +1,4 @@
-warning: unused imports: `Duration`, `Instant`
+warning: unused imports: `Duration` and `Instant`
   --> $DIR/import_remove_line.rs:7:17
    |
 LL | use std::time::{Duration, Instant};
diff --git a/tests/ui/lint/unused/lint-unused-imports.rs b/tests/ui/lint/unused/lint-unused-imports.rs
index 88f2baa..710fb7a 100644
--- a/tests/ui/lint/unused/lint-unused-imports.rs
+++ b/tests/ui/lint/unused/lint-unused-imports.rs
@@ -10,7 +10,7 @@
 
 // Should get errors for both 'Some' and 'None'
 use std::option::Option::{Some, None};
-//~^ ERROR unused imports: `None`, `Some`
+//~^ ERROR unused imports: `None` and `Some`
 
 use test::A;       //~ ERROR unused import: `test::A`
 // Be sure that if we just bring some methods into scope that they're also
diff --git a/tests/ui/lint/unused/lint-unused-imports.stderr b/tests/ui/lint/unused/lint-unused-imports.stderr
index 07684a8..a848fb3 100644
--- a/tests/ui/lint/unused/lint-unused-imports.stderr
+++ b/tests/ui/lint/unused/lint-unused-imports.stderr
@@ -10,7 +10,7 @@
 LL | #![deny(unused_imports)]
    |         ^^^^^^^^^^^^^^
 
-error: unused imports: `None`, `Some`
+error: unused imports: `None` and `Some`
   --> $DIR/lint-unused-imports.rs:12:27
    |
 LL | use std::option::Option::{Some, None};
diff --git a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr
index add85b2..1ff5c8d 100644
--- a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr
+++ b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr
@@ -13,7 +13,7 @@
    = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
    = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = help: `///` is for documentation comments. For a plain comment, use `//`.
+   = help: `///` is used for outer documentation comments; for a plain comment, use `//`
 
 error: unused doc comment
   --> $DIR/unused-doc-comments-edge-cases.rs:6:9
diff --git a/tests/ui/lint/unused/unused-macro-rules-compile-error.rs b/tests/ui/lint/unused/unused-macro-rules-compile-error.rs
index 4d51db8..0c8fe65 100644
--- a/tests/ui/lint/unused/unused-macro-rules-compile-error.rs
+++ b/tests/ui/lint/unused/unused-macro-rules-compile-error.rs
@@ -9,7 +9,7 @@
     // Some nested use
     (two_) => { foo(compile_error!("foo")); };
     (three) => { 3 };
-    (four) => { 4 }; //~ ERROR: rule of macro
+    (four) => { 4 }; //~ ERROR: rule #5 of macro
 }
 const _NUM: u8 = num!(one) + num!(three);
 
@@ -17,9 +17,9 @@
 macro_rules! num2 {
     (one) => { 1 };
     // Only identifier present
-    (two) => { fn compile_error() {} }; //~ ERROR: rule of macro
+    (two) => { fn compile_error() {} }; //~ ERROR: rule #2 of macro
     // Only identifier and bang present
-    (two_) => { compile_error! }; //~ ERROR: rule of macro
+    (two_) => { compile_error! }; //~ ERROR: rule #3 of macro
     (three) => { 3 };
 }
 const _NUM2: u8 = num2!(one) + num2!(three);
diff --git a/tests/ui/lint/unused/unused-macro-rules-compile-error.stderr b/tests/ui/lint/unused/unused-macro-rules-compile-error.stderr
index 76af8c9..936428f 100644
--- a/tests/ui/lint/unused/unused-macro-rules-compile-error.stderr
+++ b/tests/ui/lint/unused/unused-macro-rules-compile-error.stderr
@@ -1,4 +1,4 @@
-error: 5th rule of macro `num` is never used
+error: rule #5 of macro `num` is never used
   --> $DIR/unused-macro-rules-compile-error.rs:12:5
    |
 LL |     (four) => { 4 };
@@ -10,13 +10,13 @@
 LL | #![deny(unused_macro_rules)]
    |         ^^^^^^^^^^^^^^^^^^
 
-error: 3rd rule of macro `num2` is never used
+error: rule #3 of macro `num2` is never used
   --> $DIR/unused-macro-rules-compile-error.rs:22:5
    |
 LL |     (two_) => { compile_error! };
    |     ^^^^^^
 
-error: 2nd rule of macro `num2` is never used
+error: rule #2 of macro `num2` is never used
   --> $DIR/unused-macro-rules-compile-error.rs:20:5
    |
 LL |     (two) => { fn compile_error() {} };
diff --git a/tests/ui/lint/unused/unused-macro-rules-decl.rs b/tests/ui/lint/unused/unused-macro-rules-decl.rs
index 537c849..ca14d58 100644
--- a/tests/ui/lint/unused/unused-macro-rules-decl.rs
+++ b/tests/ui/lint/unused/unused-macro-rules-decl.rs
@@ -6,9 +6,9 @@
 // Most simple case
 macro num {
     (one) => { 1 },
-    (two) => { 2 }, //~ ERROR: 2nd rule of macro
+    (two) => { 2 }, //~ ERROR: rule #2 of macro
     (three) => { 3 },
-    (four) => { 4 }, //~ ERROR: 4th rule of macro
+    (four) => { 4 }, //~ ERROR: rule #4 of macro
 }
 const _NUM: u8 = num!(one) + num!(three);
 
@@ -28,7 +28,7 @@
     (two) => {
         num_rec!(one) + num_rec!(one)
     },
-    (three) => { //~ ERROR: 3rd rule of macro
+    (three) => { //~ ERROR: rule #3 of macro
         num_rec!(one) + num_rec!(two)
     },
     (four) => {
diff --git a/tests/ui/lint/unused/unused-macro-rules-decl.stderr b/tests/ui/lint/unused/unused-macro-rules-decl.stderr
index 4d9b22f..10ceb39 100644
--- a/tests/ui/lint/unused/unused-macro-rules-decl.stderr
+++ b/tests/ui/lint/unused/unused-macro-rules-decl.stderr
@@ -1,4 +1,4 @@
-error: 4th rule of macro `num` is never used
+error: rule #4 of macro `num` is never used
   --> $DIR/unused-macro-rules-decl.rs:11:5
    |
 LL |     (four) => { 4 },
@@ -10,13 +10,13 @@
 LL | #![deny(unused_macro_rules)]
    |         ^^^^^^^^^^^^^^^^^^
 
-error: 2nd rule of macro `num` is never used
+error: rule #2 of macro `num` is never used
   --> $DIR/unused-macro-rules-decl.rs:9:5
    |
 LL |     (two) => { 2 },
    |     ^^^^^
 
-error: 3rd rule of macro `num_rec` is never used
+error: rule #3 of macro `num_rec` is never used
   --> $DIR/unused-macro-rules-decl.rs:31:5
    |
 LL |     (three) => {
diff --git a/tests/ui/lint/unused/unused-macro-rules.rs b/tests/ui/lint/unused/unused-macro-rules.rs
index eeaf4d1..39a882e 100644
--- a/tests/ui/lint/unused/unused-macro-rules.rs
+++ b/tests/ui/lint/unused/unused-macro-rules.rs
@@ -5,9 +5,9 @@
 // Most simple case
 macro_rules! num {
     (one) => { 1 };
-    (two) => { 2 }; //~ ERROR: 2nd rule of macro
+    (two) => { 2 }; //~ ERROR: rule #2 of macro
     (three) => { 3 };
-    (four) => { 4 }; //~ ERROR: 4th rule of macro
+    (four) => { 4 }; //~ ERROR: rule #4 of macro
 }
 const _NUM: u8 = num!(one) + num!(three);
 
@@ -27,7 +27,7 @@
     (two) => {
         num_rec!(one) + num_rec!(one)
     };
-    (three) => { //~ ERROR: 3rd rule of macro
+    (three) => { //~ ERROR: rule #3 of macro
         num_rec!(one) + num_rec!(two)
     };
     (four) => { num_rec!(two) + num_rec!(two) };
diff --git a/tests/ui/lint/unused/unused-macro-rules.stderr b/tests/ui/lint/unused/unused-macro-rules.stderr
index 2b3098a..b9258e7 100644
--- a/tests/ui/lint/unused/unused-macro-rules.stderr
+++ b/tests/ui/lint/unused/unused-macro-rules.stderr
@@ -1,4 +1,4 @@
-error: 4th rule of macro `num` is never used
+error: rule #4 of macro `num` is never used
   --> $DIR/unused-macro-rules.rs:10:5
    |
 LL |     (four) => { 4 };
@@ -10,13 +10,13 @@
 LL | #![deny(unused_macro_rules)]
    |         ^^^^^^^^^^^^^^^^^^
 
-error: 2nd rule of macro `num` is never used
+error: rule #2 of macro `num` is never used
   --> $DIR/unused-macro-rules.rs:8:5
    |
 LL |     (two) => { 2 };
    |     ^^^^^
 
-error: 3rd rule of macro `num_rec` is never used
+error: rule #3 of macro `num_rec` is never used
   --> $DIR/unused-macro-rules.rs:30:5
    |
 LL |     (three) => {
diff --git a/tests/ui/compile_error_macro.rs b/tests/ui/macros/compile_error_macro.rs
similarity index 100%
rename from tests/ui/compile_error_macro.rs
rename to tests/ui/macros/compile_error_macro.rs
diff --git a/tests/ui/compile_error_macro.stderr b/tests/ui/macros/compile_error_macro.stderr
similarity index 100%
rename from tests/ui/compile_error_macro.stderr
rename to tests/ui/macros/compile_error_macro.stderr
diff --git a/tests/ui/macros/expr_2021_inline_const.edi2021.stderr b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
new file mode 100644
index 0000000..5e88096
--- /dev/null
+++ b/tests/ui/macros/expr_2021_inline_const.edi2021.stderr
@@ -0,0 +1,32 @@
+error: no rules expected the token `const`
+  --> $DIR/expr_2021_inline_const.rs:21:12
+   |
+LL | macro_rules! m2021 {
+   | ------------------ when calling this macro
+...
+LL |     m2021!(const { 1 });
+   |            ^^^^^ no rules expected this token in macro call
+   |
+note: while trying to match meta-variable `$e:expr_2021`
+  --> $DIR/expr_2021_inline_const.rs:10:6
+   |
+LL |     ($e:expr_2021) => {
+   |      ^^^^^^^^^^^^
+
+error: no rules expected the token `const`
+  --> $DIR/expr_2021_inline_const.rs:22:12
+   |
+LL | macro_rules! m2024 {
+   | ------------------ when calling this macro
+...
+LL |     m2024!(const { 1 });
+   |            ^^^^^ no rules expected this token in macro call
+   |
+note: while trying to match meta-variable `$e:expr`
+  --> $DIR/expr_2021_inline_const.rs:16:6
+   |
+LL |     ($e:expr) => {
+   |      ^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/expr_2021_inline_const.edi2024.stderr b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
new file mode 100644
index 0000000..237ecb2
--- /dev/null
+++ b/tests/ui/macros/expr_2021_inline_const.edi2024.stderr
@@ -0,0 +1,17 @@
+error: no rules expected the token `const`
+  --> $DIR/expr_2021_inline_const.rs:21:12
+   |
+LL | macro_rules! m2021 {
+   | ------------------ when calling this macro
+...
+LL |     m2021!(const { 1 });
+   |            ^^^^^ no rules expected this token in macro call
+   |
+note: while trying to match meta-variable `$e:expr_2021`
+  --> $DIR/expr_2021_inline_const.rs:10:6
+   |
+LL |     ($e:expr_2021) => {
+   |      ^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/macros/expr_2021_inline_const.rs b/tests/ui/macros/expr_2021_inline_const.rs
new file mode 100644
index 0000000..ebc5ea3
--- /dev/null
+++ b/tests/ui/macros/expr_2021_inline_const.rs
@@ -0,0 +1,23 @@
+//@ revisions: edi2021 edi2024
+//@[edi2024]compile-flags: --edition=2024 -Z unstable-options
+//@[edi2021]compile-flags: --edition=2021
+
+// This test ensures that the inline const match only on edition 2024
+#![feature(expr_fragment_specifier_2024)]
+#![allow(incomplete_features)]
+
+macro_rules! m2021 {
+    ($e:expr_2021) => {
+        $e
+    };
+}
+
+macro_rules! m2024 {
+    ($e:expr) => {
+        $e
+    };
+}
+fn main() {
+    m2021!(const { 1 }); //~ ERROR: no rules expected the token `const`
+    m2024!(const { 1 }); //[edi2021]~ ERROR: no rules expected the token `const`
+}
diff --git a/tests/ui/macros/expr_2021_old_edition.rs b/tests/ui/macros/expr_2021_old_edition.rs
new file mode 100644
index 0000000..a771126
--- /dev/null
+++ b/tests/ui/macros/expr_2021_old_edition.rs
@@ -0,0 +1,13 @@
+//@  compile-flags: --edition=2018
+
+// This test ensures that expr_2021 is not allowed on pre-2021 editions
+
+macro_rules! m {
+    ($e:expr_2021) => { //~ ERROR: invalid fragment specifier `expr_2021`
+        $e
+    };
+}
+
+fn main() {
+    m!(()); //~ ERROR: no rules expected the token `(`
+}
diff --git a/tests/ui/macros/expr_2021_old_edition.stderr b/tests/ui/macros/expr_2021_old_edition.stderr
new file mode 100644
index 0000000..bffa8a1
--- /dev/null
+++ b/tests/ui/macros/expr_2021_old_edition.stderr
@@ -0,0 +1,26 @@
+error: invalid fragment specifier `expr_2021`
+  --> $DIR/expr_2021_old_edition.rs:6:6
+   |
+LL |     ($e:expr_2021) => {
+   |      ^^^^^^^^^^^^
+   |
+   = help: fragment specifier `expr_2021` requires Rust 2021 or later
+           valid fragment specifiers are `ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, `path`, `meta`, `tt`, `item` and `vis`
+
+error: no rules expected the token `(`
+  --> $DIR/expr_2021_old_edition.rs:12:8
+   |
+LL | macro_rules! m {
+   | -------------- when calling this macro
+...
+LL |     m!(());
+   |        ^ no rules expected this token in macro call
+   |
+note: while trying to match meta-variable `$e:ident`
+  --> $DIR/expr_2021_old_edition.rs:6:6
+   |
+LL |     ($e:expr_2021) => {
+   |      ^^^^^^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs b/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs
new file mode 100644
index 0000000..5a737b2
--- /dev/null
+++ b/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.rs
@@ -0,0 +1,11 @@
+//@  compile-flags: --edition=2024 -Z unstable-options
+
+macro_rules! m {
+    ($e:expr_2021) => { //~ ERROR: fragment specifier `expr_2021` is unstable
+        $e
+    };
+}
+
+fn main() {
+    m!(());
+}
diff --git a/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr b/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr
new file mode 100644
index 0000000..273a938
--- /dev/null
+++ b/tests/ui/macros/feature-gate-expr_fragment_specifier_2024.stderr
@@ -0,0 +1,13 @@
+error[E0658]: fragment specifier `expr_2021` is unstable
+  --> $DIR/feature-gate-expr_fragment_specifier_2024.rs:4:6
+   |
+LL |     ($e:expr_2021) => {
+   |      ^^^^^^^^^^^^
+   |
+   = note: see issue #123742 <https://github.com/rust-lang/rust/issues/123742> for more information
+   = help: add `#![feature(expr_fragment_specifier_2024)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/crashes/97006.rs b/tests/ui/macros/genercs-in-path-with-prettry-hir.rs
similarity index 83%
rename from tests/crashes/97006.rs
rename to tests/ui/macros/genercs-in-path-with-prettry-hir.rs
index c8dfa52..84370fc 100644
--- a/tests/crashes/97006.rs
+++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.rs
@@ -1,7 +1,6 @@
-//@ known-bug: #97006
 //@ compile-flags: -Zunpretty=hir
 
-#![allow(unused)]
+// issue#97006
 
 macro_rules! m {
     ($attr_path: path) => {
diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr b/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr
new file mode 100644
index 0000000..8fcc7c6
--- /dev/null
+++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stderr
@@ -0,0 +1,8 @@
+error: unexpected generic arguments in path
+  --> $DIR/genercs-in-path-with-prettry-hir.rs:12:10
+   |
+LL | m!(inline<u8>);
+   |          ^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout
new file mode 100644
index 0000000..e9ee59a
--- /dev/null
+++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout
@@ -0,0 +1,15 @@
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+//@ compile-flags: -Zunpretty=hir
+
+// issue#97006
+
+macro_rules! m { ($attr_path: path) => { #[$attr_path] fn f() {} } }
+#[
+
+inline]
+fn f() { }
+
+fn main() { }
diff --git a/tests/ui/macros/issue-98790.rs b/tests/ui/macros/issue-98790.rs
deleted file mode 100644
index b489efe..0000000
--- a/tests/ui/macros/issue-98790.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-//@ run-pass
-
-macro_rules! stringify_item {
-    ($item:item) => {
-        stringify!($item)
-    };
-}
-
-macro_rules! repro {
-    ($expr:expr) => {
-        stringify_item! {
-            pub fn repro() -> bool {
-                $expr
-            }
-        }
-    };
-}
-
-fn main() {
-    assert_eq!(
-        repro!(match () { () => true } | true),
-        "pub fn repro() -> bool { (match () { () => true, }) | true }"
-    );
-}
diff --git a/tests/ui/macros/macro-expand-within-generics-in-path.rs b/tests/ui/macros/macro-expand-within-generics-in-path.rs
new file mode 100644
index 0000000..017d515
--- /dev/null
+++ b/tests/ui/macros/macro-expand-within-generics-in-path.rs
@@ -0,0 +1,19 @@
+// issue#123911
+// issue#123912
+
+macro_rules! m {
+    ($p: path) => {
+        #[$p]
+        struct S;
+    };
+}
+
+macro_rules! p {
+    () => {};
+}
+
+m!(generic<p!()>);
+//~^ ERROR: unexpected generic arguments in path
+//~| ERROR: cannot find attribute `generic` in this scope
+
+fn main() {}
diff --git a/tests/ui/macros/macro-expand-within-generics-in-path.stderr b/tests/ui/macros/macro-expand-within-generics-in-path.stderr
new file mode 100644
index 0000000..72026c4
--- /dev/null
+++ b/tests/ui/macros/macro-expand-within-generics-in-path.stderr
@@ -0,0 +1,14 @@
+error: unexpected generic arguments in path
+  --> $DIR/macro-expand-within-generics-in-path.rs:15:11
+   |
+LL | m!(generic<p!()>);
+   |           ^^^^^^
+
+error: cannot find attribute `generic` in this scope
+  --> $DIR/macro-expand-within-generics-in-path.rs:15:4
+   |
+LL | m!(generic<p!()>);
+   |    ^^^^^^^
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/macro-span-issue-116502.rs b/tests/ui/macros/macro-span-issue-116502.rs
new file mode 100644
index 0000000..4c254289
--- /dev/null
+++ b/tests/ui/macros/macro-span-issue-116502.rs
@@ -0,0 +1,16 @@
+#![allow(dead_code)]
+#![allow(unused_variables)]
+
+fn bug() {
+    macro_rules! m {
+        () => {
+            _ //~ ERROR the placeholder `_` is not allowed within types on item signatures for structs
+        };
+    }
+    struct S<T = m!()>(m!(), T)
+    where
+        T: Trait<m!()>;
+}
+trait Trait<T> {}
+
+fn main() {}
diff --git a/tests/ui/macros/macro-span-issue-116502.stderr b/tests/ui/macros/macro-span-issue-116502.stderr
new file mode 100644
index 0000000..da02855
--- /dev/null
+++ b/tests/ui/macros/macro-span-issue-116502.stderr
@@ -0,0 +1,30 @@
+error[E0121]: the placeholder `_` is not allowed within types on item signatures for structs
+  --> $DIR/macro-span-issue-116502.rs:7:13
+   |
+LL |             _
+   |             ^
+   |             |
+   |             not allowed in type signatures
+   |             not allowed in type signatures
+   |             not allowed in type signatures
+...
+LL |     struct S<T = m!()>(m!(), T)
+   |                  ----  ---- in this macro invocation
+   |                  |
+   |                  in this macro invocation
+LL |     where
+LL |         T: Trait<m!()>;
+   |                  ---- in this macro invocation
+   |
+   = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: use type parameters instead
+   |
+LL ~             U
+LL |         };
+LL |     }
+LL ~     struct S<U>(m!(), T)
+   |
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0121`.
diff --git a/tests/ui/macros/meta-variable-depth-outside-repeat.rs b/tests/ui/macros/meta-variable-depth-outside-repeat.rs
index b7fb947..89b4706 100644
--- a/tests/ui/macros/meta-variable-depth-outside-repeat.rs
+++ b/tests/ui/macros/meta-variable-depth-outside-repeat.rs
@@ -2,8 +2,8 @@
 
 macro_rules! metavar {
     ( $i:expr ) => {
-        ${length(0)}
-        //~^ ERROR meta-variable expression `length` with depth parameter must be called inside of a macro repetition
+        ${len(0)}
+        //~^ ERROR meta-variable expression `len` with depth parameter must be called inside of a macro repetition
     };
 }
 
diff --git a/tests/ui/macros/meta-variable-depth-outside-repeat.stderr b/tests/ui/macros/meta-variable-depth-outside-repeat.stderr
index 49b5053..4299ca9 100644
--- a/tests/ui/macros/meta-variable-depth-outside-repeat.stderr
+++ b/tests/ui/macros/meta-variable-depth-outside-repeat.stderr
@@ -1,8 +1,8 @@
-error: meta-variable expression `length` with depth parameter must be called inside of a macro repetition
+error: meta-variable expression `len` with depth parameter must be called inside of a macro repetition
   --> $DIR/meta-variable-depth-outside-repeat.rs:5:10
    |
-LL |         ${length(0)}
-   |          ^^^^^^^^^^^
+LL |         ${len(0)}
+   |          ^^^^^^^^
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/macros/missing-semi.rs b/tests/ui/macros/missing-semi.rs
new file mode 100644
index 0000000..b7e90e9
--- /dev/null
+++ b/tests/ui/macros/missing-semi.rs
@@ -0,0 +1,11 @@
+#[allow(unused_macros)]
+macro_rules! foo {
+    () => {
+
+    }
+    () => {
+        //~^ ERROR expected `;`, found `(`
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/macros/missing-semi.stderr b/tests/ui/macros/missing-semi.stderr
new file mode 100644
index 0000000..0a7afe5
--- /dev/null
+++ b/tests/ui/macros/missing-semi.stderr
@@ -0,0 +1,8 @@
+error: expected `;`, found `(`
+  --> $DIR/missing-semi.rs:6:5
+   |
+LL |     () => {
+   |     ^ no rules expected this token in macro call
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/module-macro_use-arguments.rs b/tests/ui/macros/module-macro_use-arguments.rs
similarity index 100%
rename from tests/ui/module-macro_use-arguments.rs
rename to tests/ui/macros/module-macro_use-arguments.rs
diff --git a/tests/ui/module-macro_use-arguments.stderr b/tests/ui/macros/module-macro_use-arguments.stderr
similarity index 100%
rename from tests/ui/module-macro_use-arguments.stderr
rename to tests/ui/macros/module-macro_use-arguments.stderr
diff --git a/tests/ui/no-patterns-in-args-macro.rs b/tests/ui/macros/no-patterns-in-args-macro.rs
similarity index 100%
rename from tests/ui/no-patterns-in-args-macro.rs
rename to tests/ui/macros/no-patterns-in-args-macro.rs
diff --git a/tests/ui/no-patterns-in-args-macro.stderr b/tests/ui/macros/no-patterns-in-args-macro.stderr
similarity index 100%
rename from tests/ui/no-patterns-in-args-macro.stderr
rename to tests/ui/macros/no-patterns-in-args-macro.stderr
diff --git a/tests/ui/macros/nonterminal-matching.stderr b/tests/ui/macros/nonterminal-matching.stderr
index 499f9a7..d191411 100644
--- a/tests/ui/macros/nonterminal-matching.stderr
+++ b/tests/ui/macros/nonterminal-matching.stderr
@@ -1,8 +1,6 @@
 error: no rules expected the token `enum E {}`
   --> $DIR/nonterminal-matching.rs:19:10
    |
-LL | macro complex_nonterminal($nt_item: item) {
-   |                           --------------
 LL |     macro n(a $nt_item b) {
    |     --------------------- when calling this macro
 ...
diff --git a/tests/ui/macros/println-percent-prefix-num-issue-125002.rs b/tests/ui/macros/println-percent-prefix-num-issue-125002.rs
new file mode 100644
index 0000000..9f30d48
--- /dev/null
+++ b/tests/ui/macros/println-percent-prefix-num-issue-125002.rs
@@ -0,0 +1,6 @@
+fn main() {
+    println!("%100000", 1);
+    //~^ ERROR argument never used
+    println!("%     65536", 1);
+    //~^ ERROR argument never used
+}
diff --git a/tests/ui/macros/println-percent-prefix-num-issue-125002.stderr b/tests/ui/macros/println-percent-prefix-num-issue-125002.stderr
new file mode 100644
index 0000000..7575137
--- /dev/null
+++ b/tests/ui/macros/println-percent-prefix-num-issue-125002.stderr
@@ -0,0 +1,28 @@
+error: argument never used
+  --> $DIR/println-percent-prefix-num-issue-125002.rs:2:25
+   |
+LL |     println!("%100000", 1);
+   |                         ^ argument never used
+   |
+note: format specifiers use curly braces, and the conversion specifier `1` is unknown or unsupported
+  --> $DIR/println-percent-prefix-num-issue-125002.rs:2:15
+   |
+LL |     println!("%100000", 1);
+   |               ^^
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
+
+error: argument never used
+  --> $DIR/println-percent-prefix-num-issue-125002.rs:4:29
+   |
+LL |     println!("%     65536", 1);
+   |                             ^ argument never used
+   |
+note: format specifiers use curly braces, and the conversion specifier ` ` is unknown or unsupported
+  --> $DIR/println-percent-prefix-num-issue-125002.rs:4:15
+   |
+LL |     println!("%     65536", 1);
+   |               ^^
+   = note: printf formatting is not supported; see the documentation for `std::fmt`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs b/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
index 3a14e0c..131d416 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
+++ b/tests/ui/macros/rfc-3086-metavar-expr/count-and-length-are-distinct.rs
@@ -3,60 +3,55 @@
 #![feature(macro_metavar_expr)]
 
 fn main() {
-    macro_rules! one_nested_count_and_length {
+    macro_rules! one_nested_count_and_len {
         ( $( [ $( $l:literal ),* ] ),* ) => {
             [
                 // outer-most repetition
                 $(
                     // inner-most repetition
                     $(
-                        ${ignore($l)} ${index()}, ${length()},
+                        ${ignore($l)} ${index()}, ${len()},
                     )*
-                    ${count($l)}, ${index()}, ${length()},
+                    ${count($l)}, ${index()}, ${len()},
                 )*
                 ${count($l)},
             ]
         };
     }
     assert_eq!(
-        one_nested_count_and_length!(["foo"], ["bar", "baz"]),
+        one_nested_count_and_len!(["foo"], ["bar", "baz"]),
         [
             // # ["foo"]
 
             // ## inner-most repetition (first iteration)
             //
             // `index` is 0 because this is the first inner-most iteration.
-            // `length` is 1 because there is only one inner-most repetition, "foo".
+            // `len` is 1 because there is only one inner-most repetition, "foo".
             0, 1,
-
             // ## outer-most repetition (first iteration)
             //
             // `count` is 1 because of "foo", i,e, `$l` has only one repetition,
             // `index` is 0 because this is the first outer-most iteration.
-            // `length` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
+            // `len` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
             1, 0, 2,
-
             // # ["bar", "baz"]
 
             // ## inner-most repetition (first iteration)
             //
             // `index` is 0 because this is the first inner-most iteration
-            // `length` is 2 because there are repetitions, "bar" and "baz"
+            // `len` is 2 because there are repetitions, "bar" and "baz"
             0, 2,
-
             // ## inner-most repetition (second iteration)
             //
             // `index` is 1 because this is the second inner-most iteration
-            // `length` is 2 because there are repetitions, "bar" and "baz"
+            // `len` is 2 because there are repetitions, "bar" and "baz"
             1, 2,
-
             // ## outer-most repetition (second iteration)
             //
             // `count` is 2 because of "bar" and "baz", i,e, `$l` has two repetitions,
             // `index` is 1 because this is the second outer-most iteration
-            // `length` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
+            // `len` is 2 because there are 2 outer-most repetitions, ["foo"] and ["bar", "baz"]
             2, 1, 2,
-
             // # last count
 
             // Because there are a total of 3 repetitions of `$l`, "foo", "bar" and "baz"
@@ -131,7 +126,6 @@
             &[2][..],
             // t u v w x y z
             &[7][..],
-
             // (a b c) (d e f)
             &[6, 2][..],
             // (g h) (i j k l m)
@@ -142,7 +136,6 @@
             &[5, 3][..],
             // (t u v w x y z)
             &[7, 1][..],
-
             // [ (a b c) (d e f) ]
             // [ (g h) (i j k l m) ]
             // [ (n) ]
@@ -150,7 +143,6 @@
             // [ (o) (p q) (r s) ]
             // [ (t u v w x y z) ]
             &[12, 4, 2][..],
-
             // {
             //     [ (a b c) (d e f) ]
             //     [ (g h) (i j k l m) ]
@@ -165,43 +157,43 @@
     );
 
     // Grouped from the outer-most to the inner-most
-    macro_rules! three_nested_length {
+    macro_rules! three_nested_len {
         ( $( { $( [ $( ( $( $i:ident )* ) )* ] )* } )* ) => {
             &[
                 $( $( $( $(
                     &[
-                        ${ignore($i)} ${length(3)},
-                        ${ignore($i)} ${length(2)},
-                        ${ignore($i)} ${length(1)},
-                        ${ignore($i)} ${length(0)},
+                        ${ignore($i)} ${len(3)},
+                        ${ignore($i)} ${len(2)},
+                        ${ignore($i)} ${len(1)},
+                        ${ignore($i)} ${len(0)},
                     ][..],
                 )* )* )* )*
 
                 $( $( $(
                     &[
-                        ${ignore($i)} ${length(2)},
-                        ${ignore($i)} ${length(1)},
-                        ${ignore($i)} ${length(0)},
+                        ${ignore($i)} ${len(2)},
+                        ${ignore($i)} ${len(1)},
+                        ${ignore($i)} ${len(0)},
                     ][..],
                 )* )* )*
 
                 $( $(
                     &[
-                        ${ignore($i)} ${length(1)},
-                        ${ignore($i)} ${length(0)},
+                        ${ignore($i)} ${len(1)},
+                        ${ignore($i)} ${len(0)},
                     ][..],
                 )* )*
 
                 $(
                     &[
-                        ${ignore($i)} ${length(0)},
+                        ${ignore($i)} ${len(0)},
                     ][..],
                 )*
             ][..]
         }
     }
     assert_eq!(
-        three_nested_length!(
+        three_nested_len!(
             {
                 [ (a b c) (d e f) ]
                 [ (g h) (i j k l m) ]
@@ -214,45 +206,64 @@
         ),
         &[
             // a b c
-            &[2, 3, 2, 3][..], &[2, 3, 2, 3][..], &[2, 3, 2, 3][..],
+            &[2, 3, 2, 3][..],
+            &[2, 3, 2, 3][..],
+            &[2, 3, 2, 3][..],
             // d e f
-            &[2, 3, 2, 3][..], &[2, 3, 2, 3][..], &[2, 3, 2, 3][..],
+            &[2, 3, 2, 3][..],
+            &[2, 3, 2, 3][..],
+            &[2, 3, 2, 3][..],
             // g h
-            &[2, 3, 2, 2][..], &[2, 3, 2, 2][..],
+            &[2, 3, 2, 2][..],
+            &[2, 3, 2, 2][..],
             // i j k l m
-            &[2, 3, 2, 5][..], &[2, 3, 2, 5][..], &[2, 3, 2, 5][..], &[2, 3, 2, 5][..],
+            &[2, 3, 2, 5][..],
+            &[2, 3, 2, 5][..],
+            &[2, 3, 2, 5][..],
+            &[2, 3, 2, 5][..],
             &[2, 3, 2, 5][..],
             // n
             &[2, 3, 1, 1][..],
             // o
             &[2, 2, 3, 1][..],
             // p q
-            &[2, 2, 3, 2][..], &[2, 2, 3, 2][..],
+            &[2, 2, 3, 2][..],
+            &[2, 2, 3, 2][..],
             // r s
-            &[2, 2, 3, 2][..], &[2, 2, 3, 2][..],
+            &[2, 2, 3, 2][..],
+            &[2, 2, 3, 2][..],
             // t u v w x y z
-            &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..],
-            &[2, 2, 1, 7][..], &[2, 2, 1, 7][..], &[2, 2, 1, 7][..],
-
+            &[2, 2, 1, 7][..],
+            &[2, 2, 1, 7][..],
+            &[2, 2, 1, 7][..],
+            &[2, 2, 1, 7][..],
+            &[2, 2, 1, 7][..],
+            &[2, 2, 1, 7][..],
+            &[2, 2, 1, 7][..],
             // (a b c) (d e f)
-            &[2, 3, 2][..], &[2, 3, 2][..],
+            &[2, 3, 2][..],
+            &[2, 3, 2][..],
             // (g h) (i j k l m)
-            &[2, 3, 2][..], &[2, 3, 2][..],
+            &[2, 3, 2][..],
+            &[2, 3, 2][..],
             // (n)
             &[2, 3, 1][..],
             // (o) (p q) (r s)
-            &[2, 2, 3][..], &[2, 2, 3][..], &[2, 2, 3][..],
+            &[2, 2, 3][..],
+            &[2, 2, 3][..],
+            &[2, 2, 3][..],
             // (t u v w x y z)
             &[2, 2, 1][..],
-
             // [ (a b c) (d e f) ]
             // [ (g h) (i j k l m) ]
             // [ (n) ]
-            &[2, 3][..], &[2, 3][..],  &[2, 3,][..],
+            &[2, 3][..],
+            &[2, 3][..],
+            &[2, 3,][..],
             // [ (o) (p q) (r s) ]
             // [ (t u v w x y z) ]
-            &[2, 2][..], &[2, 2][..],
-
+            &[2, 2][..],
+            &[2, 2][..],
             // {
             //     [ (a b c) (d e f) ]
             //     [ (g h) (i j k l m) ]
@@ -262,10 +273,11 @@
             //     [ (o) (p q) (r s) ]
             //     [ (t u v w x y z) ]
             // }
-            &[2][..], &[2][..]
+            &[2][..],
+            &[2][..]
         ][..]
     );
 
-    // It is possible to say, to some degree, that count is an "amalgamation" of length (see
-    // each length line result and compare them with the count results)
+    // It is possible to say, to some degree, that count is an "amalgamation" of len (see
+    // each len line result and compare them with the count results)
 }
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs b/tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs
index 6464fd6..5144522 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs
+++ b/tests/ui/macros/rfc-3086-metavar-expr/feature-gate-macro_metavar_expr.rs
@@ -37,17 +37,17 @@
     };
 }
 
-/// Produce (index, length) pairs for literals in a macro repetition.
+/// Produce (index, len) pairs for literals in a macro repetition.
 /// The literal is not included in the output, so this macro uses the
 /// `ignore` meta-variable expression to create a non-expanding
 /// repetition binding.
 macro_rules! enumerate_literals {
     ( $( ($l:stmt) ),* ) => {
-        [$( ${ignore($l)} (${index()}, ${length()}) ),*]
+        [$( ${ignore($l)} (${index()}, ${len()}) ),*]
     };
 }
 
-/// Produce index and length tuples for literals in a 2-dimensional
+/// Produce index and len tuples for literals in a 2-dimensional
 /// macro repetition.
 macro_rules! enumerate_literals_2 {
     ( $( [ $( ($l:literal) ),* ] ),* ) => {
@@ -56,9 +56,9 @@
                 $(
                     (
                         ${index(1)},
-                        ${length(1)},
+                        ${len(1)},
                         ${index(0)},
-                        ${length(0)},
+                        ${len(0)},
                         $l
                     ),
                 )*
@@ -134,7 +134,6 @@
             (0, 2, 0, 3, "foo"),
             (0, 2, 1, 3, "bar"),
             (0, 2, 2, 3, "baz"),
-
             (1, 2, 0, 4, "qux"),
             (1, 2, 1, 4, "quux"),
             (1, 2, 2, 4, "quuz"),
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs b/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs
index 787b927..1d34275 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs
+++ b/tests/ui/macros/rfc-3086-metavar-expr/macro-expansion.rs
@@ -17,20 +17,20 @@
             _nested: vec![
             $(
                 Example {
-                    _indexes: &[(${index()}, ${length()})],
+                    _indexes: &[(${index()}, ${len()})],
                     _counts: &[${count($x, 0)}, ${count($x, 1)}],
                     _nested: vec![
                     $(
                         Example {
-                            _indexes: &[(${index(1)}, ${length(1)}), (${index()}, ${length()})],
+                            _indexes: &[(${index(1)}, ${len(1)}), (${index()}, ${len()})],
                             _counts: &[${count($x)}],
                             _nested: vec![
                             $(
                                 Example {
                                     _indexes: &[
-                                        (${index(2)}, ${length(2)}),
-                                        (${index(1)}, ${length(1)}),
-                                        (${index()}, ${length()})
+                                        (${index(2)}, ${len(2)}),
+                                        (${index(1)}, ${len(1)}),
+                                        (${index()}, ${len()})
                                     ],
                                     _counts: &[],
                                     _nested: vec![],
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
index d195506..0caa3ea 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
+++ b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.rs
@@ -28,9 +28,9 @@
         (
             $( $(
                 ${ignore($foo)}
-                ${length(0)}
-                ${length(10)}
-                //~^ ERROR depth parameter of meta-variable expression `length` must be less than 2
+                ${len(0)}
+                ${len(10)}
+                //~^ ERROR depth parameter of meta-variable expression `len` must be less than 2
             )* )*
         )
     };
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
index f757b8a..0b441cad 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
+++ b/tests/ui/macros/rfc-3086-metavar-expr/out-of-bounds-arguments.stderr
@@ -10,11 +10,11 @@
 LL |                 ${index(10)},
    |                  ^^^^^^^^^^^
 
-error: depth parameter of meta-variable expression `length` must be less than 2
+error: depth parameter of meta-variable expression `len` must be less than 2
   --> $DIR/out-of-bounds-arguments.rs:32:18
    |
-LL |                 ${length(10)}
-   |                  ^^^^^^^^^^^^
+LL |                 ${len(10)}
+   |                  ^^^^^^^^^
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs
index 53d0457..77c165e 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs
+++ b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.rs
@@ -32,13 +32,12 @@
     }};
 }
 
-macro_rules! length {
+macro_rules! len {
     ( $( $e:stmt ),* ) => {
-        $( ${ignore($e)} ${length()} )*
+        $( ${ignore($e)} ${len()} )*
         //~^ ERROR meta-variable expressions are unstable
         //~| ERROR meta-variable expressions are unstable
     };
 }
 
-fn main() {
-}
+fn main() {}
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr
index 7f4adb7..f28f822 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr
+++ b/tests/ui/macros/rfc-3086-metavar-expr/required-feature.stderr
@@ -81,7 +81,7 @@
 error[E0658]: meta-variable expressions are unstable
   --> $DIR/required-feature.rs:37:13
    |
-LL |         $( ${ignore($e)} ${length()} )*
+LL |         $( ${ignore($e)} ${len()} )*
    |             ^^^^^^^^^^^^
    |
    = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
@@ -91,8 +91,8 @@
 error[E0658]: meta-variable expressions are unstable
   --> $DIR/required-feature.rs:37:27
    |
-LL |         $( ${ignore($e)} ${length()} )*
-   |                           ^^^^^^^^^^
+LL |         $( ${ignore($e)} ${len()} )*
+   |                           ^^^^^^^
    |
    = note: see issue #83527 <https://github.com/rust-lang/rust/issues/83527> for more information
    = help: add `#![feature(macro_metavar_expr)]` to the crate attributes to enable
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
index 05c65fe..9fec546 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
+++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.rs
@@ -18,23 +18,27 @@
     //~^ ERROR `count` can not be placed inside the inner-most repetition
 }
 
+#[rustfmt::skip] // autoformatters can break a few of the error traces
 macro_rules! no_curly__no_rhs_dollar__round {
     ( $( $i:ident ),* ) => { count(i) };
     //~^ ERROR cannot find function `count` in this scope
     //~| ERROR cannot find value `i` in this scope
 }
 
+#[rustfmt::skip] // autoformatters can break a few of the error traces
 macro_rules! no_curly__no_rhs_dollar__no_round {
     ( $i:ident ) => { count(i) };
     //~^ ERROR cannot find function `count` in this scope
     //~| ERROR cannot find value `i` in this scope
 }
 
+#[rustfmt::skip] // autoformatters can break a few of the error traces
 macro_rules! no_curly__rhs_dollar__round {
     ( $( $i:ident ),* ) => { count($i) };
     //~^ ERROR variable 'i' is still repeating at this depth
 }
 
+#[rustfmt::skip] // autoformatters can break a few of the error traces
 macro_rules! no_curly__rhs_dollar__no_round {
     ( $i:ident ) => { count($i) };
     //~^ ERROR cannot find function `count` in this scope
@@ -44,7 +48,7 @@
 
 macro_rules! dollar_dollar_in_the_lhs {
     ( $$ $a:ident ) => {
-    //~^ ERROR unexpected token: $
+        //~^ ERROR unexpected token: $
     };
 }
 
@@ -85,7 +89,7 @@
 }
 
 macro_rules! metavar_in_the_lhs {
-    ( ${ length() } ) => {
+    ( ${ len() } ) => {
         //~^ ERROR unexpected token: {
         //~| ERROR expected one of: `*`, `+`, or `?`
     };
@@ -109,6 +113,7 @@
     //~| ERROR expected expression, found `$`
 }
 
+#[rustfmt::skip]
 macro_rules! open_brackets_without_tokens {
     ( $( $i:ident ),* ) => { ${ {} } };
     //~^ ERROR expected expression, found `$`
diff --git a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
index 0dda382..e9cef5e 100644
--- a/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
+++ b/tests/ui/macros/rfc-3086-metavar-expr/syntax-errors.stderr
@@ -1,200 +1,200 @@
 error: unexpected token: $
-  --> $DIR/syntax-errors.rs:46:8
+  --> $DIR/syntax-errors.rs:50:8
    |
 LL |     ( $$ $a:ident ) => {
    |        ^
 
 note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions
-  --> $DIR/syntax-errors.rs:46:8
+  --> $DIR/syntax-errors.rs:50:8
    |
 LL |     ( $$ $a:ident ) => {
    |        ^
 
 error: unexpected token: a
-  --> $DIR/syntax-errors.rs:53:19
+  --> $DIR/syntax-errors.rs:57:19
    |
 LL |         ${count() a b c}
    |                   ^
    |
 note: meta-variable expression must not have trailing tokens
-  --> $DIR/syntax-errors.rs:53:19
+  --> $DIR/syntax-errors.rs:57:19
    |
 LL |         ${count() a b c}
    |                   ^
 
 error: unexpected token: a
-  --> $DIR/syntax-errors.rs:56:20
+  --> $DIR/syntax-errors.rs:60:20
    |
 LL |         ${count($i a b c)}
    |                    ^
    |
 note: meta-variable expression must not have trailing tokens
-  --> $DIR/syntax-errors.rs:56:20
+  --> $DIR/syntax-errors.rs:60:20
    |
 LL |         ${count($i a b c)}
    |                    ^
 
 error: unexpected token: a
-  --> $DIR/syntax-errors.rs:58:23
+  --> $DIR/syntax-errors.rs:62:23
    |
 LL |         ${count($i, 1 a b c)}
    |                       ^
    |
 note: meta-variable expression must not have trailing tokens
-  --> $DIR/syntax-errors.rs:58:23
+  --> $DIR/syntax-errors.rs:62:23
    |
 LL |         ${count($i, 1 a b c)}
    |                       ^
 
 error: unexpected token: a
-  --> $DIR/syntax-errors.rs:60:21
+  --> $DIR/syntax-errors.rs:64:21
    |
 LL |         ${count($i) a b c}
    |                     ^
    |
 note: meta-variable expression must not have trailing tokens
-  --> $DIR/syntax-errors.rs:60:21
+  --> $DIR/syntax-errors.rs:64:21
    |
 LL |         ${count($i) a b c}
    |                     ^
 
 error: unexpected token: a
-  --> $DIR/syntax-errors.rs:63:22
+  --> $DIR/syntax-errors.rs:67:22
    |
 LL |         ${ignore($i) a b c}
    |                      ^
    |
 note: meta-variable expression must not have trailing tokens
-  --> $DIR/syntax-errors.rs:63:22
+  --> $DIR/syntax-errors.rs:67:22
    |
 LL |         ${ignore($i) a b c}
    |                      ^
 
 error: unexpected token: a
-  --> $DIR/syntax-errors.rs:65:21
+  --> $DIR/syntax-errors.rs:69:21
    |
 LL |         ${ignore($i a b c)}
    |                     ^
    |
 note: meta-variable expression must not have trailing tokens
-  --> $DIR/syntax-errors.rs:65:21
+  --> $DIR/syntax-errors.rs:69:21
    |
 LL |         ${ignore($i a b c)}
    |                     ^
 
 error: unexpected token: a
-  --> $DIR/syntax-errors.rs:68:19
+  --> $DIR/syntax-errors.rs:72:19
    |
 LL |         ${index() a b c}
    |                   ^
    |
 note: meta-variable expression must not have trailing tokens
-  --> $DIR/syntax-errors.rs:68:19
+  --> $DIR/syntax-errors.rs:72:19
    |
 LL |         ${index() a b c}
    |                   ^
 
 error: unexpected token: a
-  --> $DIR/syntax-errors.rs:70:19
+  --> $DIR/syntax-errors.rs:74:19
    |
 LL |         ${index(1 a b c)}
    |                   ^
    |
 note: meta-variable expression must not have trailing tokens
-  --> $DIR/syntax-errors.rs:70:19
+  --> $DIR/syntax-errors.rs:74:19
    |
 LL |         ${index(1 a b c)}
    |                   ^
 
 error: unexpected token: a
-  --> $DIR/syntax-errors.rs:73:19
+  --> $DIR/syntax-errors.rs:77:19
    |
 LL |         ${index() a b c}
    |                   ^
    |
 note: meta-variable expression must not have trailing tokens
-  --> $DIR/syntax-errors.rs:73:19
+  --> $DIR/syntax-errors.rs:77:19
    |
 LL |         ${index() a b c}
    |                   ^
 
 error: unexpected token: a
-  --> $DIR/syntax-errors.rs:75:19
+  --> $DIR/syntax-errors.rs:79:19
    |
 LL |         ${index(1 a b c)}
    |                   ^
    |
 note: meta-variable expression must not have trailing tokens
-  --> $DIR/syntax-errors.rs:75:19
+  --> $DIR/syntax-errors.rs:79:19
    |
 LL |         ${index(1 a b c)}
    |                   ^
 
 error: meta-variable expression depth must be a literal
-  --> $DIR/syntax-errors.rs:82:33
+  --> $DIR/syntax-errors.rs:86:33
    |
 LL |     ( $( $i:ident ),* ) => { ${ index(IDX) } };
    |                                 ^^^^^
 
 error: unexpected token: {
-  --> $DIR/syntax-errors.rs:88:8
+  --> $DIR/syntax-errors.rs:92:8
    |
-LL |     ( ${ length() } ) => {
-   |        ^^^^^^^^^^^^
+LL |     ( ${ len() } ) => {
+   |        ^^^^^^^^^
 
 note: `$$` and meta-variable expressions are not allowed inside macro parameter definitions
-  --> $DIR/syntax-errors.rs:88:8
+  --> $DIR/syntax-errors.rs:92:8
    |
-LL |     ( ${ length() } ) => {
-   |        ^^^^^^^^^^^^
+LL |     ( ${ len() } ) => {
+   |        ^^^^^^^^^
 
 error: expected one of: `*`, `+`, or `?`
-  --> $DIR/syntax-errors.rs:88:8
+  --> $DIR/syntax-errors.rs:92:8
    |
-LL |     ( ${ length() } ) => {
-   |        ^^^^^^^^^^^^
+LL |     ( ${ len() } ) => {
+   |        ^^^^^^^^^
 
 error: meta-variables within meta-variable expressions must be referenced using a dollar sign
-  --> $DIR/syntax-errors.rs:95:33
+  --> $DIR/syntax-errors.rs:99:33
    |
 LL |     ( $( $i:ident ),* ) => { ${ ignore() } };
    |                                 ^^^^^^
 
 error: only unsuffixes integer literals are supported in meta-variable expressions
-  --> $DIR/syntax-errors.rs:101:33
+  --> $DIR/syntax-errors.rs:105:33
    |
 LL |     ( $( $i:ident ),* ) => { ${ index(1u32) } };
    |                                 ^^^^^
 
 error: meta-variable expression parameter must be wrapped in parentheses
-  --> $DIR/syntax-errors.rs:107:33
+  --> $DIR/syntax-errors.rs:111:33
    |
 LL |     ( $( $i:ident ),* ) => { ${ count{i} } };
    |                                 ^^^^^
 
-error: expected identifier
-  --> $DIR/syntax-errors.rs:113:31
-   |
-LL |     ( $( $i:ident ),* ) => { ${ {} } };
-   |                               ^^^^^^
-
 error: meta-variables within meta-variable expressions must be referenced using a dollar sign
-  --> $DIR/syntax-errors.rs:120:11
+  --> $DIR/syntax-errors.rs:125:11
    |
 LL |         ${count(foo)}
    |           ^^^^^
 
 error: meta-variables within meta-variable expressions must be referenced using a dollar sign
-  --> $DIR/syntax-errors.rs:128:11
+  --> $DIR/syntax-errors.rs:133:11
    |
 LL |         ${ignore(bar)}
    |           ^^^^^^
 
 error: unrecognized meta-variable expression
-  --> $DIR/syntax-errors.rs:135:33
+  --> $DIR/syntax-errors.rs:140:33
    |
 LL |     ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
-   |                                 ^^^^^^^^^^^^^^ help: supported expressions are count, ignore, index and length
+   |                                 ^^^^^^^^^^^^^^ help: supported expressions are count, ignore, index and len
+
+error: expected identifier
+  --> $DIR/syntax-errors.rs:118:31
+   |
+LL |     ( $( $i:ident ),* ) => { ${ {} } };
+   |                               ^^^^^^
 
 error: `count` can not be placed inside the inner-most repetition
   --> $DIR/syntax-errors.rs:12:24
@@ -209,13 +209,13 @@
    |                        ^^^^^^^^^^^^^
 
 error: variable 'i' is still repeating at this depth
-  --> $DIR/syntax-errors.rs:34:36
+  --> $DIR/syntax-errors.rs:37:36
    |
 LL |     ( $( $i:ident ),* ) => { count($i) };
    |                                    ^^
 
 error: expected expression, found `$`
-  --> $DIR/syntax-errors.rs:53:9
+  --> $DIR/syntax-errors.rs:57:9
    |
 LL |         ${count() a b c}
    |         ^ expected expression
@@ -226,7 +226,7 @@
    = note: this error originates in the macro `extra_garbage_after_metavar` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected expression, found `$`
-  --> $DIR/syntax-errors.rs:82:30
+  --> $DIR/syntax-errors.rs:86:30
    |
 LL |     ( $( $i:ident ),* ) => { ${ index(IDX) } };
    |                              ^ expected expression
@@ -237,7 +237,7 @@
    = note: this error originates in the macro `metavar_depth_is_not_literal` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected expression, found `$`
-  --> $DIR/syntax-errors.rs:95:30
+  --> $DIR/syntax-errors.rs:99:30
    |
 LL |     ( $( $i:ident ),* ) => { ${ ignore() } };
    |                              ^ expected expression
@@ -248,7 +248,7 @@
    = note: this error originates in the macro `metavar_token_without_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected expression, found `$`
-  --> $DIR/syntax-errors.rs:101:30
+  --> $DIR/syntax-errors.rs:105:30
    |
 LL |     ( $( $i:ident ),* ) => { ${ index(1u32) } };
    |                              ^ expected expression
@@ -259,7 +259,7 @@
    = note: this error originates in the macro `metavar_with_literal_suffix` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected expression, found `$`
-  --> $DIR/syntax-errors.rs:107:30
+  --> $DIR/syntax-errors.rs:111:30
    |
 LL |     ( $( $i:ident ),* ) => { ${ count{i} } };
    |                              ^ expected expression
@@ -270,7 +270,7 @@
    = note: this error originates in the macro `metavar_without_parens` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected expression, found `$`
-  --> $DIR/syntax-errors.rs:113:30
+  --> $DIR/syntax-errors.rs:118:30
    |
 LL |     ( $( $i:ident ),* ) => { ${ {} } };
    |                              ^ expected expression
@@ -281,7 +281,7 @@
    = note: this error originates in the macro `open_brackets_without_tokens` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected expression, found `$`
-  --> $DIR/syntax-errors.rs:120:9
+  --> $DIR/syntax-errors.rs:125:9
    |
 LL |         ${count(foo)}
    |         ^ expected expression
@@ -292,7 +292,7 @@
    = note: this error originates in the macro `unknown_count_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected expression, found `$`
-  --> $DIR/syntax-errors.rs:128:9
+  --> $DIR/syntax-errors.rs:133:9
    |
 LL |         ${ignore(bar)}
    |         ^ expected expression
@@ -303,7 +303,7 @@
    = note: this error originates in the macro `unknown_ignore_ident` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: expected expression, found `$`
-  --> $DIR/syntax-errors.rs:135:30
+  --> $DIR/syntax-errors.rs:140:30
    |
 LL |     ( $( $i:ident ),* ) => { ${ aaaaaaaaaaaaaa(i) } };
    |                              ^ expected expression
@@ -314,7 +314,7 @@
    = note: this error originates in the macro `unknown_metavar` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0425]: cannot find value `i` in this scope
-  --> $DIR/syntax-errors.rs:22:36
+  --> $DIR/syntax-errors.rs:23:36
    |
 LL |     ( $( $i:ident ),* ) => { count(i) };
    |                                    ^ not found in this scope
@@ -325,7 +325,7 @@
    = note: this error originates in the macro `no_curly__no_rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0425]: cannot find value `i` in this scope
-  --> $DIR/syntax-errors.rs:28:29
+  --> $DIR/syntax-errors.rs:30:29
    |
 LL |     ( $i:ident ) => { count(i) };
    |                             ^ not found in this scope
@@ -336,13 +336,13 @@
    = note: this error originates in the macro `no_curly__no_rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0425]: cannot find value `a` in this scope
-  --> $DIR/syntax-errors.rs:147:37
+  --> $DIR/syntax-errors.rs:152:37
    |
 LL |     no_curly__rhs_dollar__no_round!(a);
    |                                     ^ not found in this scope
 
 error[E0425]: cannot find function `count` in this scope
-  --> $DIR/syntax-errors.rs:22:30
+  --> $DIR/syntax-errors.rs:23:30
    |
 LL |     ( $( $i:ident ),* ) => { count(i) };
    |                              ^^^^^ not found in this scope
@@ -353,7 +353,7 @@
    = note: this error originates in the macro `no_curly__no_rhs_dollar__round` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0425]: cannot find function `count` in this scope
-  --> $DIR/syntax-errors.rs:28:23
+  --> $DIR/syntax-errors.rs:30:23
    |
 LL |     ( $i:ident ) => { count(i) };
    |                       ^^^^^ not found in this scope
@@ -364,7 +364,7 @@
    = note: this error originates in the macro `no_curly__no_rhs_dollar__no_round` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0425]: cannot find function `count` in this scope
-  --> $DIR/syntax-errors.rs:39:23
+  --> $DIR/syntax-errors.rs:43:23
    |
 LL |     ( $i:ident ) => { count($i) };
    |                       ^^^^^ not found in this scope
diff --git a/tests/ui/macros/stringify.rs b/tests/ui/macros/stringify.rs
index 492bd24..6b215ba 100644
--- a/tests/ui/macros/stringify.rs
+++ b/tests/ui/macros/stringify.rs
@@ -213,6 +213,21 @@
         "match () { _ => ({ 1 }) - 1, }",
         "match () { _ => { 1 } - 1 }",
     );
+    c2_match_arm!(
+        [ m!() - 1 ],
+        "match () { _ => m!() - 1, }",
+        "match () { _ => m!() - 1 }",
+    );
+    c2_match_arm!(
+        [ m![] - 1 ],
+        "match () { _ => m![] - 1, }",
+        "match () { _ => m![] - 1 }",
+    );
+    c2_match_arm!(
+        [ m! {} - 1 ],
+        "match () { _ => m! {} - 1, }",
+        "match () { _ => m! {} - 1 }",
+    );
 
     // ExprKind::Closure
     c1!(expr, [ || {} ], "|| {}");
@@ -660,6 +675,11 @@
         "let (a, b): (u32, u32) = (1, 2);",
         "let (a, b): (u32, u32) = (1, 2)"
     );
+    c2!(stmt,
+        [ let _ = f() else { return; } ],
+        "let _ = f() else { return; };",
+        "let _ = f() else { return; }",
+    );
     macro_rules! c2_let_expr_minus_one {
         ([ $expr:expr ], $stmt_expected:expr, $tokens_expected:expr $(,)?) => {
             c2!(stmt, [ let _ = $expr - 1 ], $stmt_expected, $tokens_expected);
@@ -670,6 +690,16 @@
         "let _ = match void {} - 1;",
         "let _ = match void {} - 1",
     );
+    macro_rules! c2_let_expr_else_return {
+        ([ $expr:expr ], $stmt_expected:expr, $tokens_expected:expr $(,)?) => {
+            c2!(stmt, [ let _ = $expr else { return; } ], $stmt_expected, $tokens_expected);
+        };
+    }
+    c2_let_expr_else_return!(
+        [ f() ],
+        "let _ = f() else { return; };",
+        "let _ = f() else { return; }",
+    );
 
     // StmtKind::Item
     c1!(stmt, [ struct S; ], "struct S;");
@@ -720,6 +750,21 @@
         "(loop { break 1; }) - 1;",
         "loop { break 1; } - 1",
     );
+    c2_minus_one!(
+        [ m!() ],
+        "m!() - 1;",
+        "m!() - 1"
+    );
+    c2_minus_one!(
+        [ m![] ],
+        "m![] - 1;",
+        "m![] - 1"
+    );
+    c2_minus_one!(
+        [ m! {} ],
+        "(m! {}) - 1;",
+        "m! {} - 1"
+    );
 
     // StmtKind::Empty
     c1!(stmt, [ ; ], ";");
diff --git a/tests/ui/macros/trace_faulty_macros.stderr b/tests/ui/macros/trace_faulty_macros.stderr
index 6960760..665dcc7 100644
--- a/tests/ui/macros/trace_faulty_macros.stderr
+++ b/tests/ui/macros/trace_faulty_macros.stderr
@@ -73,14 +73,10 @@
   --> $DIR/trace_faulty_macros.rs:49:37
    |
 LL |     (let $p:pat = $e:expr) => {test!(($p,$e))};
-   |                   -------                -- this is interpreted as expression, but it is expected to be pattern
-   |                   |
-   |                   this macro fragment matcher is expression
+   |                                          -- this is interpreted as expression, but it is expected to be pattern
 ...
 LL |     (($p:pat, $e:pat)) => {let $p = $e;};
-   |               ------                ^^ expected expression
-   |               |
-   |               this macro fragment matcher is pattern
+   |                                     ^^ expected expression
 ...
 LL |     test!(let x = 1+1);
    |     ------------------
diff --git a/tests/ui/malformed/malformed-regressions.rs b/tests/ui/malformed/malformed-regressions.rs
index ac1444b..f0a7aac 100644
--- a/tests/ui/malformed/malformed-regressions.rs
+++ b/tests/ui/malformed/malformed-regressions.rs
@@ -1,8 +1,8 @@
-#[doc] //~ ERROR attribute must be of the form
+#[doc] //~ ERROR valid forms for the attribute are
 //~^ WARN this was previously accepted
-#[ignore()] //~ ERROR attribute must be of the form
+#[ignore()] //~ ERROR valid forms for the attribute are
 //~^ WARN this was previously accepted
-#[inline = ""] //~ ERROR attribute must be of the form
+#[inline = ""] //~ ERROR valid forms for the attribute are
 //~^ WARN this was previously accepted
 #[link] //~ ERROR attribute must be of the form
 //~^ WARN this was previously accepted
diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr
index 9bfbe7e..e1dbdb9 100644
--- a/tests/ui/malformed/malformed-regressions.stderr
+++ b/tests/ui/malformed/malformed-regressions.stderr
@@ -1,4 +1,4 @@
-error: attribute must be of the form `#[doc(hidden|inline|...)]` or `#[doc = "string"]`
+error: valid forms for the attribute are `#[doc(hidden|inline|...)]` and `#[doc = "string"]`
   --> $DIR/malformed-regressions.rs:1:1
    |
 LL | #[doc]
@@ -8,7 +8,7 @@
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
    = note: `#[deny(ill_formed_attribute_input)]` on by default
 
-error: attribute must be of the form `#[ignore]` or `#[ignore = "reason"]`
+error: valid forms for the attribute are `#[ignore]` and `#[ignore = "reason"]`
   --> $DIR/malformed-regressions.rs:3:1
    |
 LL | #[ignore()]
@@ -17,7 +17,7 @@
    = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #57571 <https://github.com/rust-lang/rust/issues/57571>
 
-error: attribute must be of the form `#[inline]` or `#[inline(always|never)]`
+error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]`
   --> $DIR/malformed-regressions.rs:5:1
    |
 LL | #[inline = ""]
diff --git a/tests/ui/match/issue-82392.stdout b/tests/ui/match/issue-82392.stdout
index 8a23d90..8949611 100644
--- a/tests/ui/match/issue-82392.stdout
+++ b/tests/ui/match/issue-82392.stdout
@@ -7,10 +7,10 @@
 //@ check-pass
 
 fn main() ({
-        (if (true as bool)
-                ({ } as
-                    ()) else if (let Some(a) =
-                       ((Some as
-                               fn(i32) -> Option<i32> {Option::<i32>::Some})((3 as i32)) as
-                           Option<i32>) as bool) ({ } as ()) as ())
-               } as ())
+    (if (true as bool)
+            ({ } as
+                ()) else if (let Some(a) =
+                   ((Some as
+                           fn(i32) -> Option<i32> {Option::<i32>::Some})((3 as i32)) as
+                       Option<i32>) as bool) ({ } as ()) as ())
+           } as ())
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs
index f1ac3e3..62e4f82 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024.rs
@@ -53,6 +53,12 @@
     if let Some(&Some(Some(&x))) = &Some(Some(&mut Some(0))) {
         let _: u32 = x;
     }
+    if let Some(&Some(&x)) = Some(&Some(&mut 0)) {
+        let _: u32 = x;
+    }
+    if let Some(&Some(x)) = &mut Some(Some(0)) {
+        let _: u32 = x;
+    }
 
     let &mut x = &&mut 0;
     let _: &u32 = x;
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs
index ec091bb..96b4ff7 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.rs
@@ -14,18 +14,20 @@
         let _: &mut u32 = x;
         //~^ ERROR: mismatched types
     }
-    if let Some(&Some(&_)) = Some(&Some(&mut 0)) {
-        //~^ ERROR: mismatched types
-    }
     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
         //~^ ERROR: mismatched types
     }
     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
         //~^ ERROR: mismatched types
     }
+    if let Some(&mut Some(x)) = &Some(Some(0)) {
+        //~^ ERROR: mismatched types
+    }
+    if let Some(&mut Some(x)) = &Some(Some(0)) {
+        //~^ ERROR: mismatched types
+    }
 
-
-    let &mut _= &&0;
+    let &mut _ = &&0;
     //~^ ERROR: mismatched types
 
     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr
index be71ee6..e06a645 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail.stderr
@@ -34,17 +34,6 @@
 error[E0308]: mismatched types
   --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:17:23
    |
-LL |     if let Some(&Some(&_)) = Some(&Some(&mut 0)) {
-   |                       ^^     ------------------- this expression has type `Option<&Option<&mut {integer}>>`
-   |                       |
-   |                       types differ in mutability
-   |
-   = note: expected mutable reference `&mut {integer}`
-                      found reference `&_`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:20:23
-   |
 LL |     if let Some(&Some(&mut _)) = &mut Some(&Some(0)) {
    |                       ^^^^^^     ------------------- this expression has type `&mut Option<&Option<{integer}>>`
    |                       |
@@ -54,7 +43,7 @@
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:23:29
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:20:29
    |
 LL |     if let Some(&Some(Some((&mut _)))) = &Some(Some(&mut Some(0))) {
    |                             ^^^^^^       ------------------------- this expression has type `&Option<Option<&mut Option<{integer}>>>`
@@ -65,10 +54,32 @@
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:28:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:23:17
    |
-LL |     let &mut _= &&0;
-   |         ^^^^^^  --- this expression has type `&&{integer}`
+LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
+   |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
+   |                 |
+   |                 expected `Option<{integer}>`, found `&mut _`
+   |
+   = note:           expected enum `Option<{integer}>`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:26:17
+   |
+LL |     if let Some(&mut Some(x)) = &Some(Some(0)) {
+   |                 ^^^^^^^^^^^^    -------------- this expression has type `&Option<Option<{integer}>>`
+   |                 |
+   |                 expected `Option<{integer}>`, found `&mut _`
+   |
+   = note:           expected enum `Option<{integer}>`
+           found mutable reference `&mut _`
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:30:9
+   |
+LL |     let &mut _ = &&0;
+   |         ^^^^^^   --- this expression has type `&&{integer}`
    |         |
    |         expected integer, found `&mut _`
    |
@@ -76,7 +87,7 @@
            found mutable reference `&mut _`
 
 error[E0308]: mismatched types
-  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:31:9
+  --> $DIR/ref_pat_eat_one_layer_2024_fail.rs:33:9
    |
 LL |     let &mut _ = &&&&&&&&&&&&&&&&&&&&&&&&&&&&0;
    |         ^^^^^^   ----------------------------- this expression has type `&&&&&&&&&&&&&&&&&&&&&&&&&&&&{integer}`
@@ -86,6 +97,6 @@
    = note:           expected type `{integer}`
            found mutable reference `&mut _`
 
-error: aborting due to 8 previous errors
+error: aborting due to 9 previous errors
 
 For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs
index 3645548..3cdf47c 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.rs
@@ -8,4 +8,7 @@
         //~^ ERROR: cannot move out of a shared reference [E0507]
         let _: &u32 = x;
     }
+
+    let &ref mut x = &0;
+    //~^ cannot borrow data in a `&` reference as mutable [E0596]
 }
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr
index ccfb5c7..8b86fa6 100644
--- a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_fail2.stderr
@@ -12,6 +12,13 @@
 LL |     if let Some(&Some(ref x)) = Some(&Some(&mut 0)) {
    |                       +++
 
-error: aborting due to 1 previous error
+error[E0596]: cannot borrow data in a `&` reference as mutable
+  --> $DIR/ref_pat_eat_one_layer_2024_fail2.rs:12:10
+   |
+LL |     let &ref mut x = &0;
+   |          ^^^^^^^^^ cannot borrow as mutable
 
-For more information about this error, try `rustc --explain E0507`.
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0507, E0596.
+For more information about an error, try `rustc --explain E0507`.
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed
new file mode 100644
index 0000000..bc7a58a
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.fixed
@@ -0,0 +1,30 @@
+//@ edition: 2024
+//@ compile-flags: -Zunstable-options
+//@ run-rustfix
+#![allow(incomplete_features)]
+#![feature(ref_pat_eat_one_layer_2024)]
+
+pub fn main() {
+    if let Some(&mut Some(ref mut x)) = &mut Some(Some(0)) {
+        //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+        let _: &mut u8 = x;
+    }
+
+    if let &mut Some(Some(ref mut x)) = &mut Some(Some(0)) {
+        //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+        let _: &mut u8 = x;
+    }
+
+    macro_rules! pat {
+        ($var:ident) => { ref mut $var };
+    }
+    let &mut pat!(x) = &mut 0;
+    //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+    let _: &mut u8 = x;
+
+    let &mut (ref mut a, ref mut b) = &mut (true, false);
+    //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+    //~| ERROR: cannot borrow as mutable inside an `&` pattern
+    let _: &mut bool = a;
+    let _: &mut bool = b;
+}
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs
new file mode 100644
index 0000000..c6d72b0
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs
@@ -0,0 +1,30 @@
+//@ edition: 2024
+//@ compile-flags: -Zunstable-options
+//@ run-rustfix
+#![allow(incomplete_features)]
+#![feature(ref_pat_eat_one_layer_2024)]
+
+pub fn main() {
+    if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
+        //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+        let _: &mut u8 = x;
+    }
+
+    if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
+        //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+        let _: &mut u8 = x;
+    }
+
+    macro_rules! pat {
+        ($var:ident) => { ref mut $var };
+    }
+    let &pat!(x) = &mut 0;
+    //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+    let _: &mut u8 = x;
+
+    let &(ref mut a, ref mut b) = &mut (true, false);
+    //~^ ERROR: cannot borrow as mutable inside an `&` pattern
+    //~| ERROR: cannot borrow as mutable inside an `&` pattern
+    let _: &mut bool = a;
+    let _: &mut bool = b;
+}
diff --git a/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr
new file mode 100644
index 0000000..964e9f3
--- /dev/null
+++ b/tests/ui/match/ref_pat_eat_one_layer_2024/ref_pat_eat_one_layer_2024_ref_mut_inside_and.stderr
@@ -0,0 +1,43 @@
+error[E0596]: cannot borrow as mutable inside an `&` pattern
+  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:8:31
+   |
+LL |     if let Some(&Some(ref mut x)) = &mut Some(Some(0)) {
+   |                 -             ^
+   |                 |
+   |                 help: replace this `&` with `&mut`: `&mut`
+
+error[E0596]: cannot borrow as mutable inside an `&` pattern
+  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:13:31
+   |
+LL |     if let &Some(Some(ref mut x)) = &mut Some(Some(0)) {
+   |            -                  ^
+   |            |
+   |            help: replace this `&` with `&mut`: `&mut`
+
+error[E0596]: cannot borrow as mutable inside an `&` pattern
+  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:21:15
+   |
+LL |     let &pat!(x) = &mut 0;
+   |         -     ^
+   |         |
+   |         help: replace this `&` with `&mut`: `&mut`
+
+error[E0596]: cannot borrow as mutable inside an `&` pattern
+  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:25:19
+   |
+LL |     let &(ref mut a, ref mut b) = &mut (true, false);
+   |         -         ^
+   |         |
+   |         help: replace this `&` with `&mut`: `&mut`
+
+error[E0596]: cannot borrow as mutable inside an `&` pattern
+  --> $DIR/ref_pat_eat_one_layer_2024_ref_mut_inside_and.rs:25:30
+   |
+LL |     let &(ref mut a, ref mut b) = &mut (true, false);
+   |         -                    ^
+   |         |
+   |         help: replace this `&` with `&mut`: `&mut`
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0596`.
diff --git a/tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs b/tests/ui/match/ref_pat_everywhere-fail.rs
similarity index 63%
rename from tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs
rename to tests/ui/match/ref_pat_everywhere-fail.rs
index 9dd7a78..d1b1c04 100644
--- a/tests/ui/match/ref_pat_everywhere-mutability-mismatch.rs
+++ b/tests/ui/match/ref_pat_everywhere-fail.rs
@@ -5,11 +5,7 @@
         //~^ ERROR: mismatched types [E0308]
         let _: u32 = x;
     }
-    if let &Some(x) = &mut Some(0) {
-        //~^ ERROR: mismatched types [E0308]
-        let _: u32 = x;
-    }
-    if let Some(&x) = &mut Some(0) {
+    if let Some(&mut x) = Some(&0) {
         //~^ ERROR: mismatched types [E0308]
         let _: u32 = x;
     }
diff --git a/tests/ui/match/ref_pat_everywhere-fail.stderr b/tests/ui/match/ref_pat_everywhere-fail.stderr
new file mode 100644
index 0000000..25a0112
--- /dev/null
+++ b/tests/ui/match/ref_pat_everywhere-fail.stderr
@@ -0,0 +1,38 @@
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_everywhere-fail.rs:4:17
+   |
+LL |     if let Some(&x) = Some(0) {
+   |                 ^^    ------- this expression has type `Option<{integer}>`
+   |                 |
+   |                 expected integer, found `&_`
+   |
+   = note:   expected type `{integer}`
+           found reference `&_`
+help: consider removing `&` from the pattern
+   |
+LL |     if let Some(x) = Some(0) {
+   |                 ~
+
+error[E0308]: mismatched types
+  --> $DIR/ref_pat_everywhere-fail.rs:8:17
+   |
+LL |     if let Some(&mut x) = Some(&0) {
+   |                 ^^^^^^    -------- this expression has type `Option<&{integer}>`
+   |                 |
+   |                 types differ in mutability
+   |
+   = note:      expected reference `&{integer}`
+           found mutable reference `&mut _`
+note: to declare a mutable binding use: `mut x`
+  --> $DIR/ref_pat_everywhere-fail.rs:8:17
+   |
+LL |     if let Some(&mut x) = Some(&0) {
+   |                 ^^^^^^
+help: consider removing `&mut` from the pattern
+   |
+LL |     if let Some(x) = Some(&0) {
+   |                 ~
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr b/tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr
deleted file mode 100644
index d512ea5..0000000
--- a/tests/ui/match/ref_pat_everywhere-mutability-mismatch.stderr
+++ /dev/null
@@ -1,44 +0,0 @@
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:4:17
-   |
-LL |     if let Some(&x) = Some(0) {
-   |                 ^^    ------- this expression has type `Option<{integer}>`
-   |                 |
-   |                 expected integer, found `&_`
-   |
-   = note:   expected type `{integer}`
-           found reference `&_`
-help: consider removing `&` from the pattern
-   |
-LL |     if let Some(x) = Some(0) {
-   |                 ~
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:8:12
-   |
-LL |     if let &Some(x) = &mut Some(0) {
-   |            ^^^^^^^^   ------------ this expression has type `&mut Option<{integer}>`
-   |            |
-   |            types differ in mutability
-   |
-   = note: expected mutable reference `&mut Option<{integer}>`
-                      found reference `&_`
-
-error[E0308]: mismatched types
-  --> $DIR/ref_pat_everywhere-mutability-mismatch.rs:12:17
-   |
-LL |     if let Some(&x) = &mut Some(0) {
-   |                 ^^    ------------ this expression has type `&mut Option<{integer}>`
-   |                 |
-   |                 expected integer, found `&_`
-   |
-   = note:   expected type `{integer}`
-           found reference `&_`
-help: consider removing `&` from the pattern
-   |
-LL |     if let Some(x) = &mut Some(0) {
-   |                 ~
-
-error: aborting due to 3 previous errors
-
-For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/match/ref_pat_everywhere.rs b/tests/ui/match/ref_pat_everywhere.rs
index b3daca4..9a79c54 100644
--- a/tests/ui/match/ref_pat_everywhere.rs
+++ b/tests/ui/match/ref_pat_everywhere.rs
@@ -15,4 +15,10 @@
     if let Some(Some(&x)) = &Some(&mut Some(0)) {
         let _: u32 = x;
     }
+    if let &Some(x) = &mut Some(0) {
+        let _: u32 = x;
+    }
+    if let Some(&x) = &mut Some(0) {
+        let _: u32 = x;
+    }
 }
diff --git a/tests/ui/meta/meta-expected-error-wrong-rev.a.stderr b/tests/ui/meta/meta-expected-error-wrong-rev.a.stderr
index 4221dd0..a489040 100644
--- a/tests/ui/meta/meta-expected-error-wrong-rev.a.stderr
+++ b/tests/ui/meta/meta-expected-error-wrong-rev.a.stderr
@@ -1,5 +1,5 @@
 error[E0308]: mismatched types
-  --> $DIR/meta-expected-error-wrong-rev.rs:13:18
+  --> $DIR/meta-expected-error-wrong-rev.rs:14:18
    |
 LL |     let x: u32 = 22_usize;
    |            ---   ^^^^^^^^ expected `u32`, found `usize`
diff --git a/tests/ui/meta/meta-expected-error-wrong-rev.rs b/tests/ui/meta/meta-expected-error-wrong-rev.rs
index de27629..1c3a3fc 100644
--- a/tests/ui/meta/meta-expected-error-wrong-rev.rs
+++ b/tests/ui/meta/meta-expected-error-wrong-rev.rs
@@ -1,6 +1,7 @@
 //@ ignore-compare-mode-polonius
 
 //@ revisions: a
+//@ unused-revision-names: b
 //@ should-fail
 
 // This is a "meta-test" of the compilertest framework itself.  In
diff --git a/tests/ui/meta/no_std-extern-libc.rs b/tests/ui/meta/no_std-extern-libc.rs
index 919caf9..8b89e14 100644
--- a/tests/ui/meta/no_std-extern-libc.rs
+++ b/tests/ui/meta/no_std-extern-libc.rs
@@ -1,5 +1,6 @@
 // Test that `download-rustc` doesn't put duplicate copies of libc in the sysroot.
 //@ check-pass
+//@ ignore-windows doesn't necessarily have the libc crate
 #![crate_type = "lib"]
 #![no_std]
 #![feature(rustc_private)]
diff --git a/tests/ui/methods/issues/account-for-shadowed-bindings-issue-123558.rs b/tests/ui/methods/issues/account-for-shadowed-bindings-issue-123558.rs
new file mode 100644
index 0000000..a08bbf1
--- /dev/null
+++ b/tests/ui/methods/issues/account-for-shadowed-bindings-issue-123558.rs
@@ -0,0 +1,7 @@
+fn main() {
+    let x = Some(3);
+    let y = vec![1, 2];
+    if let Some(y) = x {
+        y.push(y); //~ ERROR E0599
+    }
+}
diff --git a/tests/ui/methods/issues/account-for-shadowed-bindings-issue-123558.stderr b/tests/ui/methods/issues/account-for-shadowed-bindings-issue-123558.stderr
new file mode 100644
index 0000000..aecad20
--- /dev/null
+++ b/tests/ui/methods/issues/account-for-shadowed-bindings-issue-123558.stderr
@@ -0,0 +1,17 @@
+error[E0599]: no method named `push` found for type `{integer}` in the current scope
+  --> $DIR/account-for-shadowed-bindings-issue-123558.rs:5:11
+   |
+LL |         y.push(y);
+   |           ^^^^ method not found in `{integer}`
+   |
+note: there's an earlier shadowed binding `y` of type `Vec<{integer}>` that has method `push` available
+  --> $DIR/account-for-shadowed-bindings-issue-123558.rs:3:9
+   |
+LL |     let y = vec![1, 2];
+   |         ^ `y` of type `Vec<{integer}>` that has method `push` defined earlier here
+LL |     if let Some(y) = x {
+   |                 - earlier `y` shadowed here with type `{integer}`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/ui/methods/method-lookup-order.rs b/tests/ui/methods/method-lookup-order.rs
index f794e5a..ad56da9 100644
--- a/tests/ui/methods/method-lookup-order.rs
+++ b/tests/ui/methods/method-lookup-order.rs
@@ -17,6 +17,7 @@
 // {mutbar_for_foo, valbar_for_etmut_foo} (which are lower precedent than the inherent `&mut self` method on `Foo`; e.g. b10101 *is* included.
 
 //@ revisions: b00001 b00010 b00011 b00100 b00101 b00110 b00111 b01000 b01001 b01100 b01101 b10000 b10001 b10010 b10011 b10101 b10111 b11000 b11001 b11101
+//@ unused-revision-names: b01010 b01011 b01110 b01111 b10100 b10110 b11010 b11011 b11100 b11110 b11111
 
 //@ compile-flags: --check-cfg=cfg(inherent_mut,bar_for_foo,mutbar_for_foo)
 //@ compile-flags: --check-cfg=cfg(valbar_for_et_foo,valbar_for_etmut_foo)
diff --git a/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.rs b/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.rs
new file mode 100644
index 0000000..b6bc450
--- /dev/null
+++ b/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.rs
@@ -0,0 +1,163 @@
+#![allow(non_snake_case)]
+
+// Ensures that we don't spend an unnecessary amount of compiler time building
+// suggestions for mistyped methods. This used to happen because when we had method
+// lookup failures, we would do subsequent method lookups, and those would themselves
+// do extra work that was unnecessary for the purposes of suggestions.
+// Fixed by #125100.
+
+macro_rules! traits {
+    ($($name:ident),*) => {
+        $(
+            trait $name {
+                fn $name(&self);
+            }
+        )*
+    }
+}
+
+traits!(
+    A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20,
+    A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31, A32, A33, A34, A35, A36, A37, A38, A39,
+    A40, A41, A42, A43, A44, A45, A46, A47, A48, A49, A50, A51, A52, A53, A54, A55, A56, A57, A58,
+    A59, A60, A61, A62, A63, A64, A65, A66, A67, A68, A69, A70, A71, A72, A73, A74, A75, A76, A77,
+    A78, A79, A80, A81, A82, A83, A84, A85, A86, A87, A88, A89, A90, A91, A92, A93, A94, A95, A96,
+    A97, A98, A99, A100, A101, A102, A103, A104, A105, A106, A107, A108, A109, A110, A111, A112,
+    A113, A114, A115, A116, A117, A118, A119, A120, A121, A122, A123, A124, A125, A126, A127, A128,
+    A129, A130, A131, A132, A133, A134, A135, A136, A137, A138, A139, A140, A141, A142, A143, A144,
+    A145, A146, A147, A148, A149, A150, A151, A152, A153, A154, A155, A156, A157, A158, A159, A160,
+    A161, A162, A163, A164, A165, A166, A167, A168, A169, A170, A171, A172, A173, A174, A175, A176,
+    A177, A178, A179, A180, A181, A182, A183, A184, A185, A186, A187, A188, A189, A190, A191, A192,
+    A193, A194, A195, A196, A197, A198, A199, A200, A201, A202, A203, A204, A205, A206, A207, A208,
+    A209, A210, A211, A212, A213, A214, A215, A216, A217, A218, A219, A220, A221, A222, A223, A224,
+    A225, A226, A227, A228, A229, A230, A231, A232, A233, A234, A235, A236, A237, A238, A239, A240,
+    A241, A242, A243, A244, A245, A246, A247, A248, A249, A250, A251, A252, A253, A254, A255, A256,
+    A257, A258, A259, A260, A261, A262, A263, A264, A265, A266, A267, A268, A269, A270, A271, A272,
+    A273, A274, A275, A276, A277, A278, A279, A280, A281, A282, A283, A284, A285, A286, A287, A288,
+    A289, A290, A291, A292, A293, A294, A295, A296, A297, A298, A299, A300, A301, A302, A303, A304,
+    A305, A306, A307, A308, A309, A310, A311, A312, A313, A314, A315, A316, A317, A318, A319, A320,
+    A321, A322, A323, A324, A325, A326, A327, A328, A329, A330, A331, A332, A333, A334, A335, A336,
+    A337, A338, A339, A340, A341, A342, A343, A344, A345, A346, A347, A348, A349, A350, A351, A352,
+    A353, A354, A355, A356, A357, A358, A359, A360, A361, A362, A363, A364, A365, A366, A367, A368,
+    A369, A370, A371, A372, A373, A374, A375, A376, A377, A378, A379, A380, A381, A382, A383, A384,
+    A385, A386, A387, A388, A389, A390, A391, A392, A393, A394, A395, A396, A397, A398, A399, A400,
+    A401, A402, A403, A404, A405, A406, A407, A408, A409, A410, A411, A412, A413, A414, A415, A416,
+    A417, A418, A419, A420, A421, A422, A423, A424, A425, A426, A427, A428, A429, A430, A431, A432,
+    A433, A434, A435, A436, A437, A438, A439, A440, A441, A442, A443, A444, A445, A446, A447, A448,
+    A449, A450, A451, A452, A453, A454, A455, A456, A457, A458, A459, A460, A461, A462, A463, A464,
+    A465, A466, A467, A468, A469, A470, A471, A472, A473, A474, A475, A476, A477, A478, A479, A480,
+    A481, A482, A483, A484, A485, A486, A487, A488, A489, A490, A491, A492, A493, A494, A495, A496,
+    A497, A498, A499, A500, A501, A502, A503, A504, A505, A506, A507, A508, A509, A510, A511, A512,
+    A513, A514, A515, A516, A517, A518, A519, A520, A521, A522, A523, A524, A525, A526, A527, A528,
+    A529, A530, A531, A532, A533, A534, A535, A536, A537, A538, A539, A540, A541, A542, A543, A544,
+    A545, A546, A547, A548, A549, A550, A551, A552, A553, A554, A555, A556, A557, A558, A559, A560,
+    A561, A562, A563, A564, A565, A566, A567, A568, A569, A570, A571, A572, A573, A574, A575, A576,
+    A577, A578, A579, A580, A581, A582, A583, A584, A585, A586, A587, A588, A589, A590, A591, A592,
+    A593, A594, A595, A596, A597, A598, A599, A600, A601, A602, A603, A604, A605, A606, A607, A608,
+    A609, A610, A611, A612, A613, A614, A615, A616, A617, A618, A619, A620, A621, A622, A623, A624,
+    A625, A626, A627, A628, A629, A630, A631, A632, A633, A634, A635, A636, A637, A638, A639, A640,
+    A641, A642, A643, A644, A645, A646, A647, A648, A649, A650, A651, A652, A653, A654, A655, A656,
+    A657, A658, A659, A660, A661, A662, A663, A664, A665, A666, A667, A668, A669, A670, A671, A672,
+    A673, A674, A675, A676, A677, A678, A679, A680, A681, A682, A683, A684, A685, A686, A687, A688,
+    A689, A690, A691, A692, A693, A694, A695, A696, A697, A698, A699, A700, A701, A702, A703, A704,
+    A705, A706, A707, A708, A709, A710, A711, A712, A713, A714, A715, A716, A717, A718, A719, A720,
+    A721, A722, A723, A724, A725, A726, A727, A728, A729, A730, A731, A732, A733, A734, A735, A736,
+    A737, A738, A739, A740, A741, A742, A743, A744, A745, A746, A747, A748, A749, A750, A751, A752,
+    A753, A754, A755, A756, A757, A758, A759, A760, A761, A762, A763, A764, A765, A766, A767, A768,
+    A769, A770, A771, A772, A773, A774, A775, A776, A777, A778, A779, A780, A781, A782, A783, A784,
+    A785, A786, A787, A788, A789, A790, A791, A792, A793, A794, A795, A796, A797, A798, A799, A800,
+    A801, A802, A803, A804, A805, A806, A807, A808, A809, A810, A811, A812, A813, A814, A815, A816,
+    A817, A818, A819, A820, A821, A822, A823, A824, A825, A826, A827, A828, A829, A830, A831, A832,
+    A833, A834, A835, A836, A837, A838, A839, A840, A841, A842, A843, A844, A845, A846, A847, A848,
+    A849, A850, A851, A852, A853, A854, A855, A856, A857, A858, A859, A860, A861, A862, A863, A864,
+    A865, A866, A867, A868, A869, A870, A871, A872, A873, A874, A875, A876, A877, A878, A879, A880,
+    A881, A882, A883, A884, A885, A886, A887, A888, A889, A890, A891, A892, A893, A894, A895, A896,
+    A897, A898, A899, A900, A901, A902, A903, A904, A905, A906, A907, A908, A909, A910, A911, A912,
+    A913, A914, A915, A916, A917, A918, A919, A920, A921, A922, A923, A924, A925, A926, A927, A928,
+    A929, A930, A931, A932, A933, A934, A935, A936, A937, A938, A939, A940, A941, A942, A943, A944,
+    A945, A946, A947, A948, A949, A950, A951, A952, A953, A954, A955, A956, A957, A958, A959, A960,
+    A961, A962, A963, A964, A965, A966, A967, A968, A969, A970, A971, A972, A973, A974, A975, A976,
+    A977, A978, A979, A980, A981, A982, A983, A984, A985, A986, A987, A988, A989, A990, A991, A992,
+    A993, A994, A995, A996, A997, A998, A999
+);
+
+#[derive(Default)]
+struct M0 {
+    m1: M1,
+    m2: M1,
+    m3: M1,
+    m4: M1,
+    m5: M1,
+    m6: M1,
+    m7: M1,
+    m8: M1,
+    m9: M1,
+    m10: M1,
+    m11: M1,
+    m12: M1,
+    m13: M1,
+    m14: M1,
+    m15: M1,
+}
+
+#[derive(Default)]
+struct M1 {
+    m1: M2,
+    m2: M2,
+    m3: M2,
+    m4: M2,
+    m5: M2,
+    m6: M2,
+    m7: M2,
+    m8: M2,
+    m9: M2,
+    m10: M2,
+    m11: M2,
+    m12: M2,
+    m13: M2,
+    m14: M2,
+    m15: M2,
+}
+
+#[derive(Default)]
+struct M2 {
+    m1: M3,
+    m2: M3,
+    m3: M3,
+    m4: M3,
+    m5: M3,
+    m6: M3,
+    m7: M3,
+    m8: M3,
+    m9: M3,
+    m10: M3,
+    m11: M3,
+    m12: M3,
+    m13: M3,
+    m14: M3,
+    m15: M3,
+}
+
+#[derive(Default)]
+struct M3 {}
+
+fn main() {
+    M0::default().Au();
+    //~^ ERROR no method named `Au` found for struct `M0` in the current scope
+    M0::default().Au();
+    //~^ ERROR no method named `Au` found for struct `M0` in the current scope
+    M0::default().Au();
+    //~^ ERROR no method named `Au` found for struct `M0` in the current scope
+    M0::default().Au();
+    //~^ ERROR no method named `Au` found for struct `M0` in the current scope
+    M0::default().Au();
+    //~^ ERROR no method named `Au` found for struct `M0` in the current scope
+    M0::default().Au();
+    //~^ ERROR no method named `Au` found for struct `M0` in the current scope
+    M0::default().Au();
+    //~^ ERROR no method named `Au` found for struct `M0` in the current scope
+    M0::default().Au();
+    //~^ ERROR no method named `Au` found for struct `M0` in the current scope
+    M0::default().Au();
+    //~^ ERROR no method named `Au` found for struct `M0` in the current scope
+}
diff --git a/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.stderr b/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.stderr
new file mode 100644
index 0000000..f5c01ef
--- /dev/null
+++ b/tests/ui/methods/probe-for-diagnostic-doesnt-do-extra-work.stderr
@@ -0,0 +1,84 @@
+error[E0599]: no method named `Au` found for struct `M0` in the current scope
+  --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:145:19
+   |
+LL | struct M0 {
+   | --------- method `Au` not found for this struct
+...
+LL |     M0::default().Au();
+   |                   ^^ method not found in `M0`
+
+error[E0599]: no method named `Au` found for struct `M0` in the current scope
+  --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:147:19
+   |
+LL | struct M0 {
+   | --------- method `Au` not found for this struct
+...
+LL |     M0::default().Au();
+   |                   ^^ method not found in `M0`
+
+error[E0599]: no method named `Au` found for struct `M0` in the current scope
+  --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:149:19
+   |
+LL | struct M0 {
+   | --------- method `Au` not found for this struct
+...
+LL |     M0::default().Au();
+   |                   ^^ method not found in `M0`
+
+error[E0599]: no method named `Au` found for struct `M0` in the current scope
+  --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:151:19
+   |
+LL | struct M0 {
+   | --------- method `Au` not found for this struct
+...
+LL |     M0::default().Au();
+   |                   ^^ method not found in `M0`
+
+error[E0599]: no method named `Au` found for struct `M0` in the current scope
+  --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:153:19
+   |
+LL | struct M0 {
+   | --------- method `Au` not found for this struct
+...
+LL |     M0::default().Au();
+   |                   ^^ method not found in `M0`
+
+error[E0599]: no method named `Au` found for struct `M0` in the current scope
+  --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:155:19
+   |
+LL | struct M0 {
+   | --------- method `Au` not found for this struct
+...
+LL |     M0::default().Au();
+   |                   ^^ method not found in `M0`
+
+error[E0599]: no method named `Au` found for struct `M0` in the current scope
+  --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:157:19
+   |
+LL | struct M0 {
+   | --------- method `Au` not found for this struct
+...
+LL |     M0::default().Au();
+   |                   ^^ method not found in `M0`
+
+error[E0599]: no method named `Au` found for struct `M0` in the current scope
+  --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:159:19
+   |
+LL | struct M0 {
+   | --------- method `Au` not found for this struct
+...
+LL |     M0::default().Au();
+   |                   ^^ method not found in `M0`
+
+error[E0599]: no method named `Au` found for struct `M0` in the current scope
+  --> $DIR/probe-for-diagnostic-doesnt-do-extra-work.rs:161:19
+   |
+LL | struct M0 {
+   | --------- method `Au` not found for this struct
+...
+LL |     M0::default().Au();
+   |                   ^^ method not found in `M0`
+
+error: aborting due to 9 previous errors
+
+For more information about this error, try `rustc --explain E0599`.
diff --git a/tests/crashes/118185-2.rs b/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.rs
similarity index 84%
rename from tests/crashes/118185-2.rs
rename to tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.rs
index c3a29c3..fd41bee 100644
--- a/tests/crashes/118185-2.rs
+++ b/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.rs
@@ -1,9 +1,8 @@
-//@ known-bug: #118185
-
 fn main() {
     let target: Target = create_target();
     target.get(0); // correct arguments work
-    target.get(10.0); // CRASH HERE
+    target.get(10.0); // (used to crash here)
+    //~^ ERROR mismatched types
 }
 
 // must be generic
diff --git a/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.stderr b/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.stderr
new file mode 100644
index 0000000..0f86916
--- /dev/null
+++ b/tests/ui/mismatched_types/diagnostic-method-lookup-returns-sig-with-fewer-args.stderr
@@ -0,0 +1,17 @@
+error[E0308]: mismatched types
+  --> $DIR/diagnostic-method-lookup-returns-sig-with-fewer-args.rs:4:16
+   |
+LL |     target.get(10.0); // (used to crash here)
+   |            --- ^^^^ expected `i32`, found floating-point number
+   |            |
+   |            arguments to this method are incorrect
+   |
+note: method defined here
+  --> $DIR/diagnostic-method-lookup-returns-sig-with-fewer-args.rs:22:12
+   |
+LL |     pub fn get(&self, data: i32) {
+   |            ^^^        ---------
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/mismatched_types/non_zero_assigned_something.rs b/tests/ui/mismatched_types/non_zero_assigned_something.rs
index d2adbe0..e94d524 100644
--- a/tests/ui/mismatched_types/non_zero_assigned_something.rs
+++ b/tests/ui/mismatched_types/non_zero_assigned_something.rs
@@ -1,9 +1,9 @@
 fn main() {
-    let _: std::num::NonZeroU64 = 1;
+    let _: std::num::NonZero<u64> = 1;
     //~^ ERROR mismatched types
-    //~| HELP  consider calling `NonZeroU64::new`
+    //~| HELP  consider calling `NonZero::new`
 
-    let _: Option<std::num::NonZeroU64> = 1;
+    let _: Option<std::num::NonZero<u64>> = 1;
     //~^ ERROR mismatched types
-    //~| HELP  consider calling `NonZeroU64::new`
+    //~| HELP  consider calling `NonZero::new`
 }
diff --git a/tests/ui/mismatched_types/non_zero_assigned_something.stderr b/tests/ui/mismatched_types/non_zero_assigned_something.stderr
index f8e8690..aa015bd 100644
--- a/tests/ui/mismatched_types/non_zero_assigned_something.stderr
+++ b/tests/ui/mismatched_types/non_zero_assigned_something.stderr
@@ -1,32 +1,32 @@
 error[E0308]: mismatched types
-  --> $DIR/non_zero_assigned_something.rs:2:35
+  --> $DIR/non_zero_assigned_something.rs:2:37
    |
-LL |     let _: std::num::NonZeroU64 = 1;
-   |            --------------------   ^ expected `NonZero<u64>`, found integer
+LL |     let _: std::num::NonZero<u64> = 1;
+   |            ----------------------   ^ expected `NonZero<u64>`, found integer
    |            |
    |            expected due to this
    |
    = note: expected struct `NonZero<u64>`
                 found type `{integer}`
-help: consider calling `NonZeroU64::new`
+help: consider calling `NonZero::new`
    |
-LL |     let _: std::num::NonZeroU64 = NonZeroU64::new(1).unwrap();
-   |                                   ++++++++++++++++ ++++++++++
+LL |     let _: std::num::NonZero<u64> = NonZero::new(1).unwrap();
+   |                                     +++++++++++++ ++++++++++
 
 error[E0308]: mismatched types
-  --> $DIR/non_zero_assigned_something.rs:6:43
+  --> $DIR/non_zero_assigned_something.rs:6:45
    |
-LL |     let _: Option<std::num::NonZeroU64> = 1;
-   |            ----------------------------   ^ expected `Option<NonZero<u64>>`, found integer
+LL |     let _: Option<std::num::NonZero<u64>> = 1;
+   |            ------------------------------   ^ expected `Option<NonZero<u64>>`, found integer
    |            |
    |            expected due to this
    |
    = note: expected enum `Option<NonZero<u64>>`
               found type `{integer}`
-help: consider calling `NonZeroU64::new`
+help: consider calling `NonZero::new`
    |
-LL |     let _: Option<std::num::NonZeroU64> = NonZeroU64::new(1);
-   |                                           ++++++++++++++++ +
+LL |     let _: Option<std::num::NonZero<u64>> = NonZero::new(1);
+   |                                             +++++++++++++ +
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs
index 0ae498c..d65bfee 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.rs
@@ -7,6 +7,7 @@
     if false {
         unsafe { mem::zeroed() }
         //~^ warn: never type fallback affects this call to an `unsafe` function
+        //~| warn: this will change its meaning in a future release!
     } else {
         return;
     };
@@ -21,6 +22,7 @@
             struct Zst;
             core::mem::transmute(Zst)
             //~^ warn: never type fallback affects this call to an `unsafe` function
+            //~| warn: this will change its meaning in a future release!
         }
     } else {
         return;
@@ -36,6 +38,7 @@
 
         unsafe { Union { a: () }.b }
         //~^ warn: never type fallback affects this union access
+        //~| warn: this will change its meaning in a future release!
     } else {
         return;
     };
@@ -45,6 +48,7 @@
     if false {
         unsafe { *ptr::from_ref(&()).cast() }
         //~^ warn: never type fallback affects this raw pointer dereference
+        //~| warn: this will change its meaning in a future release!
     } else {
         return;
     };
@@ -62,6 +66,7 @@
 
         unsafe { internally_create(x) }
         //~^ warn: never type fallback affects this call to an `unsafe` function
+        //~| warn: this will change its meaning in a future release!
 
         x.unwrap()
     } else {
@@ -73,9 +78,11 @@
     if false {
         let zeroed = mem::zeroed;
         //~^ warn: never type fallback affects this `unsafe` function
+        //~| warn: this will change its meaning in a future release!
 
         unsafe { zeroed() }
         //~^ warn: never type fallback affects this call to an `unsafe` function
+        //~| warn: this will change its meaning in a future release!
     } else {
         return;
     };
@@ -90,6 +97,7 @@
         let x = None;
         let f = internally_create;
         //~^ warn: never type fallback affects this `unsafe` function
+        //~| warn: this will change its meaning in a future release!
 
         unsafe { f(x) }
 
@@ -113,6 +121,7 @@
         unsafe {
             S(marker::PhantomData).create_out_of_thin_air()
             //~^ warn: never type fallback affects this call to an `unsafe` method
+            //~| warn: this will change its meaning in a future release!
         }
     } else {
         return;
@@ -129,6 +138,7 @@
         () => {
             match send_message::<_ /* ?0 */>() {
                 //~^ warn: never type fallback affects this call to an `unsafe` function
+                //~| warn: this will change its meaning in a future release!
                 Ok(x) => x,
                 Err(_) => loop {},
             }
diff --git a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr
index 84c9385..fbd92f8 100644
--- a/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr
+++ b/tests/ui/never_type/lint-never-type-fallback-flowing-into-unsafe.stderr
@@ -4,75 +4,93 @@
 LL |         unsafe { mem::zeroed() }
    |                  ^^^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
    = note: `#[warn(never_type_fallback_flowing_into_unsafe)]` on by default
 
 warning: never type fallback affects this call to an `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:22:13
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:23:13
    |
 LL |             core::mem::transmute(Zst)
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this union access
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:37:18
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:39:18
    |
 LL |         unsafe { Union { a: () }.b }
    |                  ^^^^^^^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this raw pointer dereference
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:46:18
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:49:18
    |
 LL |         unsafe { *ptr::from_ref(&()).cast() }
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this call to an `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:63:18
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:67:18
    |
 LL |         unsafe { internally_create(x) }
    |                  ^^^^^^^^^^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this call to an `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:77:18
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:83:18
    |
 LL |         unsafe { zeroed() }
    |                  ^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:74:22
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:79:22
    |
 LL |         let zeroed = mem::zeroed;
    |                      ^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:91:17
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:98:17
    |
 LL |         let f = internally_create;
    |                 ^^^^^^^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this call to an `unsafe` method
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:114:13
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:122:13
    |
 LL |             S(marker::PhantomData).create_out_of_thin_air()
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
 
 warning: never type fallback affects this call to an `unsafe` function
-  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:130:19
+  --> $DIR/lint-never-type-fallback-flowing-into-unsafe.rs:139:19
    |
 LL |             match send_message::<_ /* ?0 */>() {
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -80,6 +98,8 @@
 LL |         msg_send!();
    |         ----------- in this macro invocation
    |
+   = warning: this will change its meaning in a future release!
+   = note: for more information, see issue #123748 <https://github.com/rust-lang/rust/issues/123748>
    = help: specify the type explicitly
    = note: this warning originates in the macro `msg_send` (in Nightly builds, run with -Z macro-backtrace for more info)
 
diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.rs b/tests/ui/parser/attribute/attr-bad-meta-4.rs
index cedbd1d..2a69ae5 100644
--- a/tests/ui/parser/attribute/attr-bad-meta-4.rs
+++ b/tests/ui/parser/attribute/attr-bad-meta-4.rs
@@ -1,12 +1,17 @@
 macro_rules! mac {
     ($attr_item: meta) => {
         #[cfg($attr_item)]
-        //~^ ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
-        //~| ERROR expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
+        //~^ ERROR expected unsuffixed literal, found `an(arbitrary token stream)`
+        //~| ERROR expected unsuffixed literal, found `an(arbitrary token stream)`
         struct S;
     }
 }
 
 mac!(an(arbitrary token stream));
 
+#[cfg(feature = -1)]
+//~^ ERROR expected unsuffixed literal, found `-`
+//~| ERROR expected unsuffixed literal, found `-`
+fn handler() {}
+
 fn main() {}
diff --git a/tests/ui/parser/attribute/attr-bad-meta-4.stderr b/tests/ui/parser/attribute/attr-bad-meta-4.stderr
index a543bcb..192be28 100644
--- a/tests/ui/parser/attribute/attr-bad-meta-4.stderr
+++ b/tests/ui/parser/attribute/attr-bad-meta-4.stderr
@@ -1,4 +1,10 @@
-error: expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
+error: expected unsuffixed literal, found `-`
+  --> $DIR/attr-bad-meta-4.rs:12:17
+   |
+LL | #[cfg(feature = -1)]
+   |                 ^
+
+error: expected unsuffixed literal, found `an(arbitrary token stream)`
   --> $DIR/attr-bad-meta-4.rs:3:15
    |
 LL |         #[cfg($attr_item)]
@@ -9,7 +15,7 @@
    |
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: expected unsuffixed literal or identifier, found `an(arbitrary token stream)`
+error: expected unsuffixed literal, found `an(arbitrary token stream)`
   --> $DIR/attr-bad-meta-4.rs:3:15
    |
 LL |         #[cfg($attr_item)]
@@ -21,5 +27,13 @@
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
    = note: this error originates in the macro `mac` (in Nightly builds, run with -Z macro-backtrace for more info)
 
-error: aborting due to 2 previous errors
+error: expected unsuffixed literal, found `-`
+  --> $DIR/attr-bad-meta-4.rs:12:17
+   |
+LL | #[cfg(feature = -1)]
+   |                 ^
+   |
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: aborting due to 4 previous errors
 
diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.fixed b/tests/ui/parser/attribute/attr-unquoted-ident.fixed
deleted file mode 100644
index bc861ef..0000000
--- a/tests/ui/parser/attribute/attr-unquoted-ident.fixed
+++ /dev/null
@@ -1,17 +0,0 @@
-//@ compile-flags: -Zdeduplicate-diagnostics=yes
-//@ run-rustfix
-
-#![allow(unexpected_cfgs)]
-
-fn main() {
-    #[cfg(key="foo")]
-    //~^ ERROR expected unsuffixed literal, found `foo`
-    //~| HELP surround the identifier with quotation marks to parse it as a string
-    println!();
-    #[cfg(key="bar")]
-    println!();
-    #[cfg(key="foo bar baz")]
-    //~^ ERROR expected unsuffixed literal, found `foo`
-    //~| HELP surround the identifier with quotation marks to parse it as a string
-    println!();
-}
diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.rs b/tests/ui/parser/attribute/attr-unquoted-ident.rs
index 8bdb860..5b15b8d 100644
--- a/tests/ui/parser/attribute/attr-unquoted-ident.rs
+++ b/tests/ui/parser/attribute/attr-unquoted-ident.rs
@@ -1,17 +1,25 @@
 //@ compile-flags: -Zdeduplicate-diagnostics=yes
-//@ run-rustfix
 
 #![allow(unexpected_cfgs)]
 
 fn main() {
     #[cfg(key=foo)]
     //~^ ERROR expected unsuffixed literal, found `foo`
-    //~| HELP surround the identifier with quotation marks to parse it as a string
+    //~| HELP surround the identifier with quotation marks to make it into a string literal
     println!();
     #[cfg(key="bar")]
     println!();
     #[cfg(key=foo bar baz)]
     //~^ ERROR expected unsuffixed literal, found `foo`
-    //~| HELP surround the identifier with quotation marks to parse it as a string
+    //~| HELP surround the identifier with quotation marks to make it into a string literal
     println!();
 }
+
+// Don't suggest surrounding `$name` or `nickname` with quotes:
+
+macro_rules! make {
+    ($name:ident) => { #[doc(alias = $name)] pub struct S; }
+    //~^ ERROR expected unsuffixed literal, found `nickname`
+}
+
+make!(nickname); //~ NOTE in this expansion
diff --git a/tests/ui/parser/attribute/attr-unquoted-ident.stderr b/tests/ui/parser/attribute/attr-unquoted-ident.stderr
index 99484a5..e0f9945 100644
--- a/tests/ui/parser/attribute/attr-unquoted-ident.stderr
+++ b/tests/ui/parser/attribute/attr-unquoted-ident.stderr
@@ -1,24 +1,35 @@
 error: expected unsuffixed literal, found `foo`
-  --> $DIR/attr-unquoted-ident.rs:7:15
+  --> $DIR/attr-unquoted-ident.rs:6:15
    |
 LL |     #[cfg(key=foo)]
    |               ^^^
    |
-help: surround the identifier with quotation marks to parse it as a string
+help: surround the identifier with quotation marks to make it into a string literal
    |
 LL |     #[cfg(key="foo")]
    |               +   +
 
 error: expected unsuffixed literal, found `foo`
-  --> $DIR/attr-unquoted-ident.rs:13:15
+  --> $DIR/attr-unquoted-ident.rs:12:15
    |
 LL |     #[cfg(key=foo bar baz)]
    |               ^^^
    |
-help: surround the identifier with quotation marks to parse it as a string
+help: surround the identifier with quotation marks to make it into a string literal
    |
 LL |     #[cfg(key="foo bar baz")]
    |               +           +
 
-error: aborting due to 2 previous errors
+error: expected unsuffixed literal, found `nickname`
+  --> $DIR/attr-unquoted-ident.rs:21:38
+   |
+LL |     ($name:ident) => { #[doc(alias = $name)] pub struct S; }
+   |                                      ^^^^^
+...
+LL | make!(nickname);
+   | --------------- in this macro invocation
+   |
+   = note: this error originates in the macro `make` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/parser/else-no-if.rs b/tests/ui/parser/else-no-if.rs
index f0b40ec..ad5262c 100644
--- a/tests/ui/parser/else-no-if.rs
+++ b/tests/ui/parser/else-no-if.rs
@@ -1,3 +1,7 @@
+macro_rules! falsy {
+    () => { false };
+}
+
 fn foo() {
     if true {
     } else false {
@@ -25,6 +29,32 @@
     {}
 }
 
+fn foo5() {
+    if true {
+    } else falsy!() {
+    //~^ ERROR expected `{`, found `falsy`
+    }
+}
+
+fn foo6() {
+    if true {
+    } else falsy!();
+    //~^ ERROR expected `{`, found `falsy`
+}
+
+fn foo7() {
+    if true {
+    } else falsy! {} {
+    //~^ ERROR expected `{`, found `falsy`
+    }
+}
+
+fn foo8() {
+    if true {
+    } else falsy! {};
+    //~^ ERROR expected `{`, found `falsy`
+}
+
 fn falsy() -> bool {
     false
 }
diff --git a/tests/ui/parser/else-no-if.stderr b/tests/ui/parser/else-no-if.stderr
index b9c1a75..2e3e8f6 100644
--- a/tests/ui/parser/else-no-if.stderr
+++ b/tests/ui/parser/else-no-if.stderr
@@ -1,5 +1,5 @@
 error: expected `{`, found keyword `false`
-  --> $DIR/else-no-if.rs:3:12
+  --> $DIR/else-no-if.rs:7:12
    |
 LL |     } else false {
    |       ---- ^^^^^
@@ -12,7 +12,7 @@
    |            ++
 
 error: expected `{`, found `falsy`
-  --> $DIR/else-no-if.rs:10:12
+  --> $DIR/else-no-if.rs:14:12
    |
 LL |     } else falsy() {
    |       ---- ^^^^^
@@ -25,7 +25,7 @@
    |            ++
 
 error: expected `{`, found `falsy`
-  --> $DIR/else-no-if.rs:17:12
+  --> $DIR/else-no-if.rs:21:12
    |
 LL |     } else falsy();
    |            ^^^^^ expected `{`
@@ -36,7 +36,7 @@
    |            +         +
 
 error: expected `{`, found keyword `loop`
-  --> $DIR/else-no-if.rs:23:12
+  --> $DIR/else-no-if.rs:27:12
    |
 LL |     } else loop{}
    |            ^^^^ expected `{`
@@ -46,5 +46,51 @@
 LL |     } else { loop{} }
    |            +        +
 
-error: aborting due to 4 previous errors
+error: expected `{`, found `falsy`
+  --> $DIR/else-no-if.rs:34:12
+   |
+LL |     } else falsy!() {
+   |       ---- ^^^^^
+   |       |
+   |       expected an `if` or a block after this `else`
+   |
+help: add an `if` if this is the condition of a chained `else if` statement
+   |
+LL |     } else if falsy!() {
+   |            ++
+
+error: expected `{`, found `falsy`
+  --> $DIR/else-no-if.rs:41:12
+   |
+LL |     } else falsy!();
+   |            ^^^^^ expected `{`
+   |
+help: try placing this code inside a block
+   |
+LL |     } else { falsy!() };
+   |            +          +
+
+error: expected `{`, found `falsy`
+  --> $DIR/else-no-if.rs:47:12
+   |
+LL |     } else falsy! {} {
+   |            ^^^^^ expected `{`
+   |
+help: try placing this code inside a block
+   |
+LL |     } else { falsy! {} } {
+   |            +           +
+
+error: expected `{`, found `falsy`
+  --> $DIR/else-no-if.rs:54:12
+   |
+LL |     } else falsy! {};
+   |            ^^^^^ expected `{`
+   |
+help: try placing this code inside a block
+   |
+LL |     } else { falsy! {} };
+   |            +           +
+
+error: aborting due to 8 previous errors
 
diff --git a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs
new file mode 100644
index 0000000..3c0059b
--- /dev/null
+++ b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.rs
@@ -0,0 +1,6 @@
+// Regression test for issue #124935
+// Tests that we do not erroneously emit an error about
+// missing main function when the mod starts with a `;`
+
+; //~ ERROR expected item, found `;`
+fn main() { }
diff --git a/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr
new file mode 100644
index 0000000..9776677
--- /dev/null
+++ b/tests/ui/parser/issues/fn-no-semicolon-issue-124935-semi-after-item.stderr
@@ -0,0 +1,8 @@
+error: expected item, found `;`
+  --> $DIR/fn-no-semicolon-issue-124935-semi-after-item.rs:5:1
+   |
+LL | ;
+   | ^ help: remove this semicolon
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/issues/issue-49040.rs b/tests/ui/parser/issues/issue-49040.rs
index b7a541d..68e7cc9 100644
--- a/tests/ui/parser/issues/issue-49040.rs
+++ b/tests/ui/parser/issues/issue-49040.rs
@@ -1,3 +1,3 @@
 #![allow(unused_variables)]; //~ ERROR expected item, found `;`
-//~^ ERROR `main` function
 fn foo() {}
+//~^ ERROR `main` function
diff --git a/tests/ui/parser/issues/issue-49040.stderr b/tests/ui/parser/issues/issue-49040.stderr
index 8af7838..11ef5e1 100644
--- a/tests/ui/parser/issues/issue-49040.stderr
+++ b/tests/ui/parser/issues/issue-49040.stderr
@@ -5,10 +5,10 @@
    |                            ^ help: remove this semicolon
 
 error[E0601]: `main` function not found in crate `issue_49040`
-  --> $DIR/issue-49040.rs:1:29
+  --> $DIR/issue-49040.rs:2:12
    |
-LL | #![allow(unused_variables)];
-   |                             ^ consider adding a `main` function to `$DIR/issue-49040.rs`
+LL | fn foo() {}
+   |            ^ consider adding a `main` function to `$DIR/issue-49040.rs`
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs
new file mode 100644
index 0000000..3fbac5f
--- /dev/null
+++ b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.rs
@@ -0,0 +1,5 @@
+// Regression test for issue #124935
+// Tests that we still emit an error after an item.
+
+fn main() { }
+; //~ ERROR expected item, found `;`
diff --git a/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr
new file mode 100644
index 0000000..2d7f540
--- /dev/null
+++ b/tests/ui/parser/issues/missing-main-issue-124935-semi-after-item.stderr
@@ -0,0 +1,10 @@
+error: expected item, found `;`
+  --> $DIR/missing-main-issue-124935-semi-after-item.rs:5:1
+   |
+LL | ;
+   | ^ help: remove this semicolon
+   |
+   = help: function declarations are not followed by a semicolon
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/parser/label-is-actually-char.rs b/tests/ui/parser/label-is-actually-char.rs
index 74df898..915ce86 100644
--- a/tests/ui/parser/label-is-actually-char.rs
+++ b/tests/ui/parser/label-is-actually-char.rs
@@ -1,4 +1,4 @@
-// Note: it's ok to interpret 'a as 'a', but but not ok to interpret 'abc as
+// Note: it's ok to interpret 'a as 'a', but not ok to interpret 'abc as
 // 'abc' because 'abc' is not a valid char literal.
 
 fn main() {
diff --git a/tests/ui/parser/macro/statement-boundaries.rs b/tests/ui/parser/macro/statement-boundaries.rs
new file mode 100644
index 0000000..67a6aa3
--- /dev/null
+++ b/tests/ui/parser/macro/statement-boundaries.rs
@@ -0,0 +1,104 @@
+//@ run-pass
+//@ edition:2021
+
+// This is a test of several uses of rustc_ast::util::classify::expr_requires_semi_to_be_stmt
+// by the Rust parser, which relates to the insertion of statement boundaries
+// after certain kinds of expressions if they appear at the head of a statement.
+
+#![allow(unused_braces, unused_unsafe)]
+
+macro_rules! unit {
+    () => {
+        { () }
+    };
+}
+
+#[derive(Copy, Clone)]
+struct X;
+
+fn main() {
+    let x = X;
+
+    // There is a statement boundary before `|x| x`, so it's a closure.
+    let _: fn(X) -> X = { if true {} |x| x };
+    let _: fn(X) -> X = { if true {} else {} |x| x };
+    let _: fn(X) -> X = { match () { () => {} } |x| x };
+    let _: fn(X) -> X = { { () } |x| x };
+    let _: fn(X) -> X = { unsafe {} |x| x };
+    let _: fn(X) -> X = { while false {} |x| x };
+    let _: fn(X) -> X = { loop { break; } |x| x };
+    let _: fn(X) -> X = { for _ in 0..0 {} |x| x };
+    let _: fn(X) -> X = { const {} |x| x };
+    let _: fn(X) -> X = { unit! {} |x| x };
+
+    // No statement boundary, so `|x| x` is 2× BitOr operation.
+    () = { "" |x| x };
+    () = { ("") |x| x };
+    () = { [""] |x| x };
+    () = { unit!() |x| x };
+    () = { unit![] |x| x };
+
+    // All the same cases, but as a match arm.
+    () = match x {
+        // Statement boundary before `| X`, which becomes a new arm with leading vert.
+        X if false => if true {} | X if false => {}
+        X if false => if true {} else {} | X if false => {}
+        X if false => match () { () => {} } | X if false => {}
+        X if false => { () } | X if false => {}
+        X if false => unsafe {} | X if false => {}
+        X if false => while false {} | X if false => {}
+        X if false => loop { break; } | X if false => {}
+        X if false => for _ in 0..0 {} | X if false => {}
+        X if false => const {} | X if false => {}
+
+        // No statement boundary, so `| X` is BitOr.
+        X if false => "" | X,
+        X if false => ("") | X,
+        X if false => [""] | X,
+        X if false => unit! {} | X, // !! inconsistent with braced mac call in statement position
+        X if false => unit!() | X,
+        X if false => unit![] | X,
+
+        X => {}
+    };
+
+    // Test how the statement boundary logic interacts with macro metavariables /
+    // "invisible delimiters".
+    macro_rules! assert_statement_boundary {
+        ($expr:expr) => {
+            let _: fn(X) -> X = { $expr |x| x };
+
+            () = match X {
+                X if false => $expr | X if false => {}
+                X => {}
+            };
+        };
+    }
+    macro_rules! assert_no_statement_boundary {
+        ($expr:expr) => {
+            () = { $expr |x| x };
+
+            () = match x {
+                X if false => $expr | X,
+                X => {}
+            };
+        };
+    }
+    assert_statement_boundary!(if true {});
+    assert_no_statement_boundary!("");
+}
+
+impl std::ops::BitOr<X> for () {
+    type Output = ();
+    fn bitor(self, _: X) {}
+}
+
+impl std::ops::BitOr<X> for &str {
+    type Output = ();
+    fn bitor(self, _: X) {}
+}
+
+impl<T, const N: usize> std::ops::BitOr<X> for [T; N] {
+    type Output = ();
+    fn bitor(self, _: X) {}
+}
diff --git a/tests/ui/parser/recover/turbofish-arg-with-stray-colon.rs b/tests/ui/parser/recover/turbofish-arg-with-stray-colon.rs
new file mode 100644
index 0000000..3212521
--- /dev/null
+++ b/tests/ui/parser/recover/turbofish-arg-with-stray-colon.rs
@@ -0,0 +1,6 @@
+fn foo() {
+    let x = Tr<A, A:>;
+    //~^ ERROR expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,`
+}
+
+fn main() {}
diff --git a/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr b/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr
new file mode 100644
index 0000000..551b2e3
--- /dev/null
+++ b/tests/ui/parser/recover/turbofish-arg-with-stray-colon.stderr
@@ -0,0 +1,14 @@
+error: expected one of `!`, `.`, `::`, `;`, `?`, `else`, `{`, or an operator, found `,`
+  --> $DIR/turbofish-arg-with-stray-colon.rs:2:17
+   |
+LL |     let x = Tr<A, A:>;
+   |                 ^ expected one of 8 possible tokens
+   |
+   = note: type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
+help: maybe write a path separator here
+   |
+LL |     let x = Tr<A, A::>;
+   |                    ~~
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/super-fast-paren-parsing.rs b/tests/ui/parser/super-fast-paren-parsing.rs
similarity index 82%
rename from tests/ui/super-fast-paren-parsing.rs
rename to tests/ui/parser/super-fast-paren-parsing.rs
index ce7283e..5b7cd6f 100644
--- a/tests/ui/super-fast-paren-parsing.rs
+++ b/tests/ui/parser/super-fast-paren-parsing.rs
@@ -3,10 +3,7 @@
 #![allow(unused_parens)]
 #![allow(non_upper_case_globals)]
 #![allow(dead_code)]
-//@ exec-env:RUST_MIN_STACK=16000000
-//@ rustc-env:RUST_MIN_STACK=16000000
-//
-// Big stack is needed for pretty printing, a little sad...
+#![cfg_attr(rustfmt, rustfmt::skip)]
 
 static a: isize =
 (((((((((((((((((((((((((((((((((((((((((((((((((((
diff --git a/tests/ui/pattern/auxiliary/match_ergonomics_2024_macros.rs b/tests/ui/pattern/auxiliary/match_ergonomics_2024_macros.rs
new file mode 100644
index 0000000..0b70e44
--- /dev/null
+++ b/tests/ui/pattern/auxiliary/match_ergonomics_2024_macros.rs
@@ -0,0 +1,12 @@
+//@ edition: 2024
+//@ compile-flags: -Z unstable-options
+
+// This contains a binding in edition 2024, so if matched with a reference binding mode it will end
+// up with a `mut ref mut` binding mode. We use this to test the migration lint on patterns with
+// mixed editions.
+#[macro_export]
+macro_rules! mixed_edition_pat {
+    ($foo:ident) => {
+        Some(mut $foo)
+    };
+}
diff --git a/tests/ui/by-move-pattern-binding.rs b/tests/ui/pattern/by-move-pattern-binding.rs
similarity index 100%
rename from tests/ui/by-move-pattern-binding.rs
rename to tests/ui/pattern/by-move-pattern-binding.rs
diff --git a/tests/ui/by-move-pattern-binding.stderr b/tests/ui/pattern/by-move-pattern-binding.stderr
similarity index 100%
rename from tests/ui/by-move-pattern-binding.stderr
rename to tests/ui/pattern/by-move-pattern-binding.stderr
diff --git a/tests/ui/fn-in-pat.rs b/tests/ui/pattern/fn-in-pat.rs
similarity index 100%
rename from tests/ui/fn-in-pat.rs
rename to tests/ui/pattern/fn-in-pat.rs
diff --git a/tests/ui/fn-in-pat.stderr b/tests/ui/pattern/fn-in-pat.stderr
similarity index 100%
rename from tests/ui/fn-in-pat.stderr
rename to tests/ui/pattern/fn-in-pat.stderr
diff --git a/tests/ui/inc-range-pat.rs b/tests/ui/pattern/inc-range-pat.rs
similarity index 100%
rename from tests/ui/inc-range-pat.rs
rename to tests/ui/pattern/inc-range-pat.rs
diff --git a/tests/ui/pattern/match_ergonomics_2024.fixed b/tests/ui/pattern/match_ergonomics_2024.fixed
new file mode 100644
index 0000000..d8dbcb2
--- /dev/null
+++ b/tests/ui/pattern/match_ergonomics_2024.fixed
@@ -0,0 +1,57 @@
+//@ edition: 2021
+//@ run-rustfix
+//@ rustfix-only-machine-applicable
+//@ aux-build:match_ergonomics_2024_macros.rs
+#![feature(mut_preserve_binding_mode_2024, ref_pat_eat_one_layer_2024)]
+#![allow(incomplete_features, unused)]
+#![deny(rust_2024_incompatible_pat)]
+
+extern crate match_ergonomics_2024_macros;
+
+struct Foo(u8);
+
+fn main() {
+    let &Foo(mut a) = &Foo(0);
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+    a = 42;
+
+    let &mut Foo(mut a) = &mut Foo(0);
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+    a = 42;
+
+    if let &&&&&Some(&_) = &&&&&Some(&0u8) {}
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+
+    if let &&&&&Some(&mut _) = &&&&&Some(&mut 0u8) {}
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+
+    if let &&&&&mut Some(&_) = &&&&&mut Some(&0u8) {}
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+
+    if let &mut Some(&mut Some(&mut Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {}
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+
+    if let &mut Some(&mut Some(&mut Some(ref mut _a))) = &mut Some(&mut Some(&mut Some(0u8))) {}
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+
+    struct Struct {
+        a: u32,
+        b: u32,
+        c: u32,
+    }
+    let s = Struct { a: 0, b: 0, c: 0 };
+    let &Struct { ref a, mut b, ref c } = &s;
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+
+    #[warn(rust_2024_incompatible_pat)]
+    match &(Some(0), Some(0)) {
+        // The two patterns are the same syntactically, but because they're defined in different
+        // editions they don't mean the same thing.
+        (Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(_y)) => {
+            //~^ WARN: the semantics of this pattern will change in edition 2024
+            _x = 4;
+            _y = &7;
+        }
+        _ => {}
+    }
+}
diff --git a/tests/ui/pattern/match_ergonomics_2024.rs b/tests/ui/pattern/match_ergonomics_2024.rs
new file mode 100644
index 0000000..38dc0c8
--- /dev/null
+++ b/tests/ui/pattern/match_ergonomics_2024.rs
@@ -0,0 +1,57 @@
+//@ edition: 2021
+//@ run-rustfix
+//@ rustfix-only-machine-applicable
+//@ aux-build:match_ergonomics_2024_macros.rs
+#![feature(mut_preserve_binding_mode_2024, ref_pat_eat_one_layer_2024)]
+#![allow(incomplete_features, unused)]
+#![deny(rust_2024_incompatible_pat)]
+
+extern crate match_ergonomics_2024_macros;
+
+struct Foo(u8);
+
+fn main() {
+    let Foo(mut a) = &Foo(0);
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+    a = 42;
+
+    let Foo(mut a) = &mut Foo(0);
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+    a = 42;
+
+    if let Some(&_) = &&&&&Some(&0u8) {}
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+
+    if let Some(&mut _) = &&&&&Some(&mut 0u8) {}
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+
+    if let Some(&_) = &&&&&mut Some(&0u8) {}
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+
+    if let Some(&mut Some(Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {}
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+
+    if let Some(&mut Some(Some(_a))) = &mut Some(&mut Some(&mut Some(0u8))) {}
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+
+    struct Struct {
+        a: u32,
+        b: u32,
+        c: u32,
+    }
+    let s = Struct { a: 0, b: 0, c: 0 };
+    let Struct { a, mut b, c } = &s;
+    //~^ ERROR: the semantics of this pattern will change in edition 2024
+
+    #[warn(rust_2024_incompatible_pat)]
+    match &(Some(0), Some(0)) {
+        // The two patterns are the same syntactically, but because they're defined in different
+        // editions they don't mean the same thing.
+        (Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(_y)) => {
+            //~^ WARN: the semantics of this pattern will change in edition 2024
+            _x = 4;
+            _y = &7;
+        }
+        _ => {}
+    }
+}
diff --git a/tests/ui/pattern/match_ergonomics_2024.stderr b/tests/ui/pattern/match_ergonomics_2024.stderr
new file mode 100644
index 0000000..1184443
--- /dev/null
+++ b/tests/ui/pattern/match_ergonomics_2024.stderr
@@ -0,0 +1,97 @@
+error: the semantics of this pattern will change in edition 2024
+  --> $DIR/match_ergonomics_2024.rs:14:9
+   |
+LL |     let Foo(mut a) = &Foo(0);
+   |         -^^^^^^^^^
+   |         |
+   |         help: desugar the match ergonomics: `&`
+   |
+note: the lint level is defined here
+  --> $DIR/match_ergonomics_2024.rs:7:9
+   |
+LL | #![deny(rust_2024_incompatible_pat)]
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+error: the semantics of this pattern will change in edition 2024
+  --> $DIR/match_ergonomics_2024.rs:18:9
+   |
+LL |     let Foo(mut a) = &mut Foo(0);
+   |         -^^^^^^^^^
+   |         |
+   |         help: desugar the match ergonomics: `&mut`
+
+error: the semantics of this pattern will change in edition 2024
+  --> $DIR/match_ergonomics_2024.rs:22:12
+   |
+LL |     if let Some(&_) = &&&&&Some(&0u8) {}
+   |            -^^^^^^^
+   |            |
+   |            help: desugar the match ergonomics: `&&&&&`
+
+error: the semantics of this pattern will change in edition 2024
+  --> $DIR/match_ergonomics_2024.rs:25:12
+   |
+LL |     if let Some(&mut _) = &&&&&Some(&mut 0u8) {}
+   |            -^^^^^^^^^^^
+   |            |
+   |            help: desugar the match ergonomics: `&&&&&`
+
+error: the semantics of this pattern will change in edition 2024
+  --> $DIR/match_ergonomics_2024.rs:28:12
+   |
+LL |     if let Some(&_) = &&&&&mut Some(&0u8) {}
+   |            -^^^^^^^
+   |            |
+   |            help: desugar the match ergonomics: `&&&&&mut`
+
+error: the semantics of this pattern will change in edition 2024
+  --> $DIR/match_ergonomics_2024.rs:31:12
+   |
+LL |     if let Some(&mut Some(Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: desugar the match ergonomics
+   |
+LL |     if let &mut Some(&mut Some(&mut Some(_))) = &mut Some(&mut Some(&mut Some(0u8))) {}
+   |            ++++                ++++
+
+error: the semantics of this pattern will change in edition 2024
+  --> $DIR/match_ergonomics_2024.rs:34:12
+   |
+LL |     if let Some(&mut Some(Some(_a))) = &mut Some(&mut Some(&mut Some(0u8))) {}
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: desugar the match ergonomics
+   |
+LL |     if let &mut Some(&mut Some(&mut Some(ref mut _a))) = &mut Some(&mut Some(&mut Some(0u8))) {}
+   |            ++++                ++++      +++++++
+
+error: the semantics of this pattern will change in edition 2024
+  --> $DIR/match_ergonomics_2024.rs:43:9
+   |
+LL |     let Struct { a, mut b, c } = &s;
+   |         ^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: desugar the match ergonomics
+   |
+LL |     let &Struct { ref a, mut b, ref c } = &s;
+   |         +         +++           +++
+
+warning: the semantics of this pattern will change in edition 2024
+  --> $DIR/match_ergonomics_2024.rs:50:9
+   |
+LL |         (Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(_y)) => {
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+note: the lint level is defined here
+  --> $DIR/match_ergonomics_2024.rs:46:12
+   |
+LL |     #[warn(rust_2024_incompatible_pat)]
+   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^
+help: desugar the match ergonomics
+   |
+LL |         &(Some(mut _x), match_ergonomics_2024_macros::mixed_edition_pat!(ref _y)) => {
+   |         +                                                                +++
+
+error: aborting due to 8 previous errors; 1 warning emitted
+
diff --git a/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.rs b/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.rs
deleted file mode 100644
index 249f251..0000000
--- a/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-//@ edition: 2021
-#![feature(mut_preserve_binding_mode_2024)]
-#![allow(incomplete_features, unused)]
-#![forbid(dereferencing_mut_binding)]
-
-struct Foo(u8);
-
-fn main() {
-    let Foo(mut a) = &Foo(0);
-    //~^ ERROR: dereferencing `mut` binding
-    a = 42;
-
-    let Foo(mut a) = &mut Foo(0);
-    //~^ ERROR: dereferencing `mut` binding
-    a = 42;
-}
diff --git a/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.stderr b/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.stderr
deleted file mode 100644
index e8d11ac..0000000
--- a/tests/ui/pattern/mut_preserve_binding_mode_2024_lint.stderr
+++ /dev/null
@@ -1,31 +0,0 @@
-error: dereferencing `mut` binding
-  --> $DIR/mut_preserve_binding_mode_2024_lint.rs:9:13
-   |
-LL |     let Foo(mut a) = &Foo(0);
-   |             ^^^^^ `mut` dereferences the type of this binding
-   |
-help: this will change in edition 2024
-  --> $DIR/mut_preserve_binding_mode_2024_lint.rs:9:13
-   |
-LL |     let Foo(mut a) = &Foo(0);
-   |             ^^^^^
-note: the lint level is defined here
-  --> $DIR/mut_preserve_binding_mode_2024_lint.rs:4:11
-   |
-LL | #![forbid(dereferencing_mut_binding)]
-   |           ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: dereferencing `mut` binding
-  --> $DIR/mut_preserve_binding_mode_2024_lint.rs:13:13
-   |
-LL |     let Foo(mut a) = &mut Foo(0);
-   |             ^^^^^ `mut` dereferences the type of this binding
-   |
-help: this will change in edition 2024
-  --> $DIR/mut_preserve_binding_mode_2024_lint.rs:13:13
-   |
-LL |     let Foo(mut a) = &mut Foo(0);
-   |             ^^^^^
-
-error: aborting due to 2 previous errors
-
diff --git a/tests/ui/no-patterns-in-args-2.rs b/tests/ui/pattern/no-patterns-in-args-2.rs
similarity index 100%
rename from tests/ui/no-patterns-in-args-2.rs
rename to tests/ui/pattern/no-patterns-in-args-2.rs
diff --git a/tests/ui/no-patterns-in-args-2.stderr b/tests/ui/pattern/no-patterns-in-args-2.stderr
similarity index 100%
rename from tests/ui/no-patterns-in-args-2.stderr
rename to tests/ui/pattern/no-patterns-in-args-2.stderr
diff --git a/tests/ui/no-patterns-in-args.rs b/tests/ui/pattern/no-patterns-in-args.rs
similarity index 100%
rename from tests/ui/no-patterns-in-args.rs
rename to tests/ui/pattern/no-patterns-in-args.rs
diff --git a/tests/ui/no-patterns-in-args.stderr b/tests/ui/pattern/no-patterns-in-args.stderr
similarity index 100%
rename from tests/ui/no-patterns-in-args.stderr
rename to tests/ui/pattern/no-patterns-in-args.stderr
diff --git a/tests/ui/pattern/skipped-ref-pats-issue-125058.rs b/tests/ui/pattern/skipped-ref-pats-issue-125058.rs
new file mode 100644
index 0000000..b733e5fd
--- /dev/null
+++ b/tests/ui/pattern/skipped-ref-pats-issue-125058.rs
@@ -0,0 +1,18 @@
+//@ run-pass
+//@ edition: 2024
+//@ compile-flags: -Zunstable-options
+
+#![allow(incomplete_features)]
+#![feature(ref_pat_eat_one_layer_2024)]
+
+struct Foo;
+//~^ WARN struct `Foo` is never constructed
+
+fn main() {
+    || {
+        //~^ WARN unused closure that must be used
+        if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+            let _: u32 = x;
+        }
+    };
+}
diff --git a/tests/ui/pattern/skipped-ref-pats-issue-125058.stderr b/tests/ui/pattern/skipped-ref-pats-issue-125058.stderr
new file mode 100644
index 0000000..cee1cc6
--- /dev/null
+++ b/tests/ui/pattern/skipped-ref-pats-issue-125058.stderr
@@ -0,0 +1,24 @@
+warning: struct `Foo` is never constructed
+  --> $DIR/skipped-ref-pats-issue-125058.rs:8:8
+   |
+LL | struct Foo;
+   |        ^^^
+   |
+   = note: `#[warn(dead_code)]` on by default
+
+warning: unused closure that must be used
+  --> $DIR/skipped-ref-pats-issue-125058.rs:12:5
+   |
+LL | /     || {
+LL | |
+LL | |         if let Some(Some(&mut x)) = &mut Some(&mut Some(0)) {
+LL | |             let _: u32 = x;
+LL | |         }
+LL | |     };
+   | |_____^
+   |
+   = note: closures are lazy and do nothing unless called
+   = note: `#[warn(unused_must_use)]` on by default
+
+warning: 2 warnings emitted
+
diff --git a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs
index 653dcab..796ba4d 100644
--- a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs
+++ b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs
@@ -6,7 +6,7 @@
     pub use self::Lieutenant::{JuniorGrade, Full};
     //~^ ERROR `JuniorGrade` is private, and cannot be re-exported
     //~| ERROR `Full` is private, and cannot be re-exported
-    //~| ERROR unused imports: `Full`, `JuniorGrade`
+    //~| ERROR unused imports: `Full` and `JuniorGrade`
     pub use self::PettyOfficer::*;
     //~^ ERROR glob import doesn't reexport anything
     //~| ERROR unused import: `self::PettyOfficer::*`
diff --git a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr
index 93a39ed..f1701d5 100644
--- a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr
+++ b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr
@@ -46,7 +46,7 @@
 LL |     pub use self::Professor::*;
    |             ^^^^^^^^^^^^^^^^^^
 
-error: unused imports: `Full`, `JuniorGrade`
+error: unused imports: `Full` and `JuniorGrade`
   --> $DIR/issue-46209-private-enum-variant-reexport.rs:6:32
    |
 LL |     pub use self::Lieutenant::{JuniorGrade, Full};
diff --git a/tests/ui/proc-macro/signature.stderr b/tests/ui/proc-macro/signature.stderr
index 2a53145..fd67944 100644
--- a/tests/ui/proc-macro/signature.stderr
+++ b/tests/ui/proc-macro/signature.stderr
@@ -2,7 +2,7 @@
   --> $DIR/signature.rs:10:1
    |
 LL | pub unsafe extern "C" fn foo(a: i32, b: u32) -> u32 {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected normal fn, found unsafe fn
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected safe fn, found unsafe fn
    |
    = note: expected signature `fn(proc_macro::TokenStream) -> proc_macro::TokenStream`
               found signature `unsafe extern "C" fn(i32, u32) -> u32`
diff --git a/tests/ui/env-args-reverse-iterator.rs b/tests/ui/process/env-args-reverse-iterator.rs
similarity index 100%
rename from tests/ui/env-args-reverse-iterator.rs
rename to tests/ui/process/env-args-reverse-iterator.rs
diff --git a/tests/ui/env-funky-keys.rs b/tests/ui/process/env-funky-keys.rs
similarity index 100%
rename from tests/ui/env-funky-keys.rs
rename to tests/ui/process/env-funky-keys.rs
diff --git a/tests/ui/process/env-null-vars.rs b/tests/ui/process/env-null-vars.rs
new file mode 100644
index 0000000..24d7835
--- /dev/null
+++ b/tests/ui/process/env-null-vars.rs
@@ -0,0 +1,16 @@
+// Ensure that env::vars() does not panic if environ is null.
+// Regression test for rust-lang/rust#53200
+//@ run-pass
+
+#![feature(rustc_private)]
+
+// FIXME: more platforms?
+#[cfg(target_os = "linux")]
+fn main() {
+    extern crate libc;
+    unsafe { libc::clearenv(); }
+    assert_eq!(std::env::vars().count(), 0);
+}
+
+#[cfg(not(target_os = "linux"))]
+fn main() {}
diff --git a/tests/ui/env-vars.rs b/tests/ui/process/env-vars.rs
similarity index 100%
rename from tests/ui/env-vars.rs
rename to tests/ui/process/env-vars.rs
diff --git a/tests/ui/exec-env.rs b/tests/ui/process/exec-env.rs
similarity index 100%
rename from tests/ui/exec-env.rs
rename to tests/ui/process/exec-env.rs
diff --git a/tests/ui/inherit-env.rs b/tests/ui/process/inherit-env.rs
similarity index 100%
rename from tests/ui/inherit-env.rs
rename to tests/ui/process/inherit-env.rs
diff --git a/tests/ui/process/no-stdio.rs b/tests/ui/process/no-stdio.rs
index 05b1e52..8eebf6d 100644
--- a/tests/ui/process/no-stdio.rs
+++ b/tests/ui/process/no-stdio.rs
@@ -5,11 +5,13 @@
 
 #![feature(rustc_private)]
 
+#[cfg(unix)]
 extern crate libc;
 
-use std::process::{Command, Stdio};
 use std::env;
+use std::ffi::c_int;
 use std::io::{self, Read, Write};
+use std::process::{Command, Stdio};
 
 #[cfg(unix)]
 unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
@@ -36,14 +38,14 @@
 }
 
 #[cfg(unix)]
-fn assert_fd_is_valid(fd: libc::c_int) {
+fn assert_fd_is_valid(fd: c_int) {
     if unsafe { libc::fcntl(fd, libc::F_GETFD) == -1 } {
         panic!("file descriptor {} is not valid: {}", fd, io::Error::last_os_error());
     }
 }
 
 #[cfg(windows)]
-fn assert_fd_is_valid(_fd: libc::c_int) {}
+fn assert_fd_is_valid(_fd: c_int) {}
 
 #[cfg(windows)]
 unsafe fn without_stdio<R, F: FnOnce() -> R>(f: F) -> R {
diff --git a/tests/ui/impossible_range.fixed b/tests/ui/range/impossible_range.fixed
similarity index 100%
rename from tests/ui/impossible_range.fixed
rename to tests/ui/range/impossible_range.fixed
diff --git a/tests/ui/impossible_range.rs b/tests/ui/range/impossible_range.rs
similarity index 100%
rename from tests/ui/impossible_range.rs
rename to tests/ui/range/impossible_range.rs
diff --git a/tests/ui/impossible_range.stderr b/tests/ui/range/impossible_range.stderr
similarity index 100%
rename from tests/ui/impossible_range.stderr
rename to tests/ui/range/impossible_range.stderr
diff --git a/tests/ui/range_inclusive.rs b/tests/ui/range/range_inclusive.rs
similarity index 100%
rename from tests/ui/range_inclusive.rs
rename to tests/ui/range/range_inclusive.rs
diff --git a/tests/ui/conflicting-repr-hints.rs b/tests/ui/repr/conflicting-repr-hints.rs
similarity index 100%
rename from tests/ui/conflicting-repr-hints.rs
rename to tests/ui/repr/conflicting-repr-hints.rs
diff --git a/tests/ui/conflicting-repr-hints.stderr b/tests/ui/repr/conflicting-repr-hints.stderr
similarity index 100%
rename from tests/ui/conflicting-repr-hints.stderr
rename to tests/ui/repr/conflicting-repr-hints.stderr
diff --git a/tests/ui/ret-bang.rs b/tests/ui/return/ret-bang.rs
similarity index 100%
rename from tests/ui/ret-bang.rs
rename to tests/ui/return/ret-bang.rs
diff --git a/tests/ui/ret-non-nil.rs b/tests/ui/return/ret-non-nil.rs
similarity index 100%
rename from tests/ui/ret-non-nil.rs
rename to tests/ui/return/ret-non-nil.rs
diff --git a/tests/ui/ret-non-nil.stderr b/tests/ui/return/ret-non-nil.stderr
similarity index 100%
rename from tests/ui/ret-non-nil.stderr
rename to tests/ui/return/ret-non-nil.stderr
diff --git a/tests/ui/return-disjoint-regions.rs b/tests/ui/return/return-disjoint-regions.rs
similarity index 100%
rename from tests/ui/return-disjoint-regions.rs
rename to tests/ui/return/return-disjoint-regions.rs
diff --git a/tests/ui/return-disjoint-regions.stderr b/tests/ui/return/return-disjoint-regions.stderr
similarity index 100%
rename from tests/ui/return-disjoint-regions.stderr
rename to tests/ui/return/return-disjoint-regions.stderr
diff --git a/tests/ui/return-nil.rs b/tests/ui/return/return-nil.rs
similarity index 100%
rename from tests/ui/return-nil.rs
rename to tests/ui/return/return-nil.rs
diff --git a/tests/ui/return/tail-expr-if-as-return.rs b/tests/ui/return/tail-expr-if-as-return.rs
new file mode 100644
index 0000000..119ffcc
--- /dev/null
+++ b/tests/ui/return/tail-expr-if-as-return.rs
@@ -0,0 +1,5 @@
+fn main() {
+    if true {
+        "" //~ ERROR mismatched types [E0308]
+    }
+}
diff --git a/tests/ui/return/tail-expr-if-as-return.stderr b/tests/ui/return/tail-expr-if-as-return.stderr
new file mode 100644
index 0000000..2631f1e
--- /dev/null
+++ b/tests/ui/return/tail-expr-if-as-return.stderr
@@ -0,0 +1,12 @@
+error[E0308]: mismatched types
+  --> $DIR/tail-expr-if-as-return.rs:3:9
+   |
+LL | /     if true {
+LL | |         ""
+   | |         ^^ expected `()`, found `&str`
+LL | |     }
+   | |_____- expected this to be `()`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.rs b/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.rs
deleted file mode 100644
index c9dc1c6..0000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-#![feature(do_not_recommend)]
-
-pub trait Foo {
-}
-
-impl Foo for i32 {
-}
-
-pub trait Bar {
-}
-
-#[do_not_recommend]
-impl<T: Foo> Bar for T {
-}
-
-fn stuff<T: Bar>(_: T) {}
-
-fn main() {
-    stuff(1u8);
-    //~^ the trait bound `u8: Bar` is not satisfied
-}
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr b/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr
deleted file mode 100644
index 284dacf..0000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/feature-gate-do_not_recommend.stderr
+++ /dev/null
@@ -1,25 +0,0 @@
-error[E0277]: the trait bound `u8: Bar` is not satisfied
-  --> $DIR/feature-gate-do_not_recommend.rs:19:11
-   |
-LL |     stuff(1u8);
-   |     ----- ^^^ the trait `Foo` is not implemented for `u8`, which is required by `u8: Bar`
-   |     |
-   |     required by a bound introduced by this call
-   |
-   = help: the trait `Foo` is implemented for `i32`
-note: required for `u8` to implement `Bar`
-  --> $DIR/feature-gate-do_not_recommend.rs:13:14
-   |
-LL | impl<T: Foo> Bar for T {
-   |         ---  ^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required by a bound in `stuff`
-  --> $DIR/feature-gate-do_not_recommend.rs:16:13
-   |
-LL | fn stuff<T: Bar>(_: T) {}
-   |             ^^^ required by this bound in `stuff`
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.rs b/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.rs
deleted file mode 100644
index 91863f5..0000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-#![feature(do_not_recommend)]
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-const CONST: () = ();
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-static Static: () = ();
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-type Type = ();
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-enum Enum {
-}
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-extern {
-}
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-fn fun() {
-}
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-struct Struct {
-}
-
-#[do_not_recommend]
-//~^ `#[do_not_recommend]` can only be placed
-trait Trait {
-}
-
-#[do_not_recommend]
-impl Trait for i32 {
-}
-
-fn main() {
-}
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.stderr b/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.stderr
deleted file mode 100644
index 01ebc23..0000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/incorrect-locations.stderr
+++ /dev/null
@@ -1,50 +0,0 @@
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:3:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:7:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:11:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:15:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:20:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:25:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:30:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: `#[do_not_recommend]` can only be placed on trait implementations
-  --> $DIR/incorrect-locations.rs:35:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 8 previous errors
-
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.rs b/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.rs
deleted file mode 100644
index f0c5c22..0000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-trait Foo {
-}
-
-#[do_not_recommend]
-//~^ ERROR the `#[do_not_recommend]` attribute is an experimental feature
-impl Foo for i32 {
-}
-
-fn main() {
-}
diff --git a/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.stderr b/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.stderr
deleted file mode 100644
index 02bc51c..0000000
--- a/tests/ui/rfcs/rfc-2397-do-not-recommend/unstable-feature.stderr
+++ /dev/null
@@ -1,13 +0,0 @@
-error[E0658]: the `#[do_not_recommend]` attribute is an experimental feature
-  --> $DIR/unstable-feature.rs:4:1
-   |
-LL | #[do_not_recommend]
-   | ^^^^^^^^^^^^^^^^^^^
-   |
-   = note: see issue #51992 <https://github.com/rust-lang/rust/issues/51992> for more information
-   = help: add `#![feature(do_not_recommend)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/runtime/on-broken-pipe/error.rs b/tests/ui/runtime/on-broken-pipe/error.rs
index ab2036c..0a02087 100644
--- a/tests/ui/runtime/on-broken-pipe/error.rs
+++ b/tests/ui/runtime/on-broken-pipe/error.rs
@@ -1,6 +1,7 @@
 //@ run-pass
 //@ aux-build:sigpipe-utils.rs
 //@ compile-flags: -Zon-broken-pipe=error
+//@ only-unix because SIGPIPE is a unix thing
 
 fn main() {
     extern crate sigpipe_utils;
diff --git a/tests/ui/runtime/on-broken-pipe/inherit.rs b/tests/ui/runtime/on-broken-pipe/inherit.rs
index 64909b7..f3c8140 100644
--- a/tests/ui/runtime/on-broken-pipe/inherit.rs
+++ b/tests/ui/runtime/on-broken-pipe/inherit.rs
@@ -4,6 +4,7 @@
 //@ aux-bin: assert-inherit-sig_ign.rs
 //@ run-pass
 //@ compile-flags: -Zon-broken-pipe=kill
+//@ only-unix because SIGPIPE is a unix thing
 
 #![feature(rustc_private)]
 
diff --git a/tests/ui/runtime/on-broken-pipe/kill.rs b/tests/ui/runtime/on-broken-pipe/kill.rs
index 5dace6f..748e53f 100644
--- a/tests/ui/runtime/on-broken-pipe/kill.rs
+++ b/tests/ui/runtime/on-broken-pipe/kill.rs
@@ -1,6 +1,7 @@
 //@ run-pass
 //@ aux-build:sigpipe-utils.rs
 //@ compile-flags: -Zon-broken-pipe=kill
+//@ only-unix because SIGPIPE is a unix thing
 
 fn main() {
     extern crate sigpipe_utils;
diff --git a/tests/ui/runtime/on-broken-pipe/not-used.rs b/tests/ui/runtime/on-broken-pipe/not-used.rs
index e31236f..22a2604 100644
--- a/tests/ui/runtime/on-broken-pipe/not-used.rs
+++ b/tests/ui/runtime/on-broken-pipe/not-used.rs
@@ -1,5 +1,6 @@
 //@ run-pass
 //@ aux-build:sigpipe-utils.rs
+//@ only-unix because SIGPIPE is a unix thing
 
 fn main() {
     extern crate sigpipe_utils;
diff --git a/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs b/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs
index c173120..c40590a 100644
--- a/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs
+++ b/tests/ui/runtime/on-broken-pipe/with-rustc_main.rs
@@ -1,6 +1,7 @@
 //@ run-pass
 //@ aux-build:sigpipe-utils.rs
 //@ compile-flags: -Zon-broken-pipe=kill
+//@ only-unix because SIGPIPE is a unix thing
 
 #![feature(rustc_attrs)]
 
diff --git a/tests/ui/runtime/out-of-stack.rs b/tests/ui/runtime/out-of-stack.rs
index ab2b50b..a62398d 100644
--- a/tests/ui/runtime/out-of-stack.rs
+++ b/tests/ui/runtime/out-of-stack.rs
@@ -8,21 +8,16 @@
 //@ ignore-fuchsia must translate zircon signal to SIGABRT, FIXME (#58590)
 //@ ignore-nto no stack overflow handler used (no alternate stack available)
 
-#![feature(core_intrinsics)]
 #![feature(rustc_private)]
 
 #[cfg(unix)]
 extern crate libc;
 
 use std::env;
+use std::hint::black_box;
 use std::process::Command;
 use std::thread;
 
-// Inlining to avoid llvm turning the recursive functions into tail calls,
-// which doesn't consume stack.
-#[inline(always)]
-pub fn black_box<T>(dummy: T) { std::intrinsics::black_box(dummy); }
-
 fn silent_recurse() {
     let buf = [0u8; 1000];
     black_box(buf);
diff --git a/tests/ui/runtime/stdout-during-shutdown.rs b/tests/ui/runtime/stdout-during-shutdown-unix.rs
similarity index 96%
rename from tests/ui/runtime/stdout-during-shutdown.rs
rename to tests/ui/runtime/stdout-during-shutdown-unix.rs
index 8549f5d..8e0f1d37 100644
--- a/tests/ui/runtime/stdout-during-shutdown.rs
+++ b/tests/ui/runtime/stdout-during-shutdown-unix.rs
@@ -1,6 +1,7 @@
 //@ run-pass
 //@ check-run-results
 //@ ignore-emscripten
+//@ only-unix
 
 // Emscripten doesn't flush its own stdout buffers on exit, which would fail
 // this test. So this test is disabled on this platform.
diff --git a/tests/ui/runtime/stdout-during-shutdown.run.stdout b/tests/ui/runtime/stdout-during-shutdown-unix.run.stdout
similarity index 100%
rename from tests/ui/runtime/stdout-during-shutdown.run.stdout
rename to tests/ui/runtime/stdout-during-shutdown-unix.run.stdout
diff --git a/tests/ui/runtime/stdout-during-shutdown-windows.rs b/tests/ui/runtime/stdout-during-shutdown-windows.rs
new file mode 100644
index 0000000..4644965
--- /dev/null
+++ b/tests/ui/runtime/stdout-during-shutdown-windows.rs
@@ -0,0 +1,20 @@
+//@ run-pass
+//@ check-run-results
+//@ only-windows
+
+struct Bye;
+
+impl Drop for Bye {
+    fn drop(&mut self) {
+        print!(", world!");
+    }
+}
+
+fn main() {
+    thread_local!{
+        static BYE: Bye = Bye;
+    }
+    BYE.with(|_| {
+        print!("hello");
+    });
+}
diff --git a/tests/ui/runtime/stdout-during-shutdown.run.stdout b/tests/ui/runtime/stdout-during-shutdown-windows.run.stdout
similarity index 100%
copy from tests/ui/runtime/stdout-during-shutdown.run.stdout
copy to tests/ui/runtime/stdout-during-shutdown-windows.run.stdout
diff --git a/tests/ui/rust-2018/async-ident.fixed b/tests/ui/rust-2018/async-ident.fixed
index 4e31f67..639a8a2 100644
--- a/tests/ui/rust-2018/async-ident.fixed
+++ b/tests/ui/rust-2018/async-ident.fixed
@@ -9,16 +9,14 @@
 
 macro_rules! foo {
     ($foo:ident) => {};
-    ($r#async:expr, r#async) => {};
+    ($async:expr, r#async) => {};
     //~^ ERROR async
-    //~| ERROR async
-    //~| WARN this is accepted in the current edition
     //~| WARN this is accepted in the current edition
 }
 
 foo!(r#async);
-    //~^ ERROR async
-    //~| WARN this is accepted in the current edition
+//~^ ERROR async
+//~| WARN this is accepted in the current edition
 
 mod dont_lint_raw {
     fn r#async() {}
diff --git a/tests/ui/rust-2018/async-ident.rs b/tests/ui/rust-2018/async-ident.rs
index 4c5134a..7921f05 100644
--- a/tests/ui/rust-2018/async-ident.rs
+++ b/tests/ui/rust-2018/async-ident.rs
@@ -11,14 +11,12 @@
     ($foo:ident) => {};
     ($async:expr, async) => {};
     //~^ ERROR async
-    //~| ERROR async
-    //~| WARN this is accepted in the current edition
     //~| WARN this is accepted in the current edition
 }
 
 foo!(async);
-    //~^ ERROR async
-    //~| WARN this is accepted in the current edition
+//~^ ERROR async
+//~| WARN this is accepted in the current edition
 
 mod dont_lint_raw {
     fn r#async() {}
diff --git a/tests/ui/rust-2018/async-ident.stderr b/tests/ui/rust-2018/async-ident.stderr
index 5b8d818..4ab061d 100644
--- a/tests/ui/rust-2018/async-ident.stderr
+++ b/tests/ui/rust-2018/async-ident.stderr
@@ -14,15 +14,6 @@
    = note: `#[deny(keyword_idents_2018)]` implied by `#[deny(keyword_idents)]`
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:12:7
-   |
-LL |     ($async:expr, async) => {};
-   |       ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
-   |
-   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
-   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
-
-error: `async` is a keyword in the 2018 edition
   --> $DIR/async-ident.rs:12:19
    |
 LL |     ($async:expr, async) => {};
@@ -32,7 +23,7 @@
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:19:6
+  --> $DIR/async-ident.rs:17:6
    |
 LL | foo!(async);
    |      ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -41,7 +32,7 @@
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:28:11
+  --> $DIR/async-ident.rs:26:11
    |
 LL |     trait async {}
    |           ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -50,7 +41,7 @@
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:32:10
+  --> $DIR/async-ident.rs:30:10
    |
 LL |     impl async for MyStruct {}
    |          ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -59,7 +50,7 @@
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:38:12
+  --> $DIR/async-ident.rs:36:12
    |
 LL |     static async: u32 = 0;
    |            ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -68,7 +59,7 @@
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:44:11
+  --> $DIR/async-ident.rs:42:11
    |
 LL |     const async: u32 = 0;
    |           ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -77,7 +68,7 @@
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:50:15
+  --> $DIR/async-ident.rs:48:15
    |
 LL | impl Foo { fn async() {} }
    |               ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -86,7 +77,7 @@
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:55:12
+  --> $DIR/async-ident.rs:53:12
    |
 LL |     struct async {}
    |            ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -95,7 +86,7 @@
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:58:9
+  --> $DIR/async-ident.rs:56:9
    |
 LL |     let async: async = async {};
    |         ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -104,7 +95,7 @@
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:58:16
+  --> $DIR/async-ident.rs:56:16
    |
 LL |     let async: async = async {};
    |                ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -113,7 +104,7 @@
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:58:24
+  --> $DIR/async-ident.rs:56:24
    |
 LL |     let async: async = async {};
    |                        ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -122,7 +113,7 @@
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:69:19
+  --> $DIR/async-ident.rs:67:19
    |
 LL |     () => (pub fn async() {})
    |                   ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -131,7 +122,7 @@
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
 error: `async` is a keyword in the 2018 edition
-  --> $DIR/async-ident.rs:76:6
+  --> $DIR/async-ident.rs:74:6
    |
 LL |     (async) => (1)
    |      ^^^^^ help: you can use a raw identifier to stay compatible: `r#async`
@@ -139,5 +130,5 @@
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2018!
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
-error: aborting due to 15 previous errors
+error: aborting due to 14 previous errors
 
diff --git a/tests/ui/rust-2024/box-slice-into-iter-ambiguous.fixed b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.fixed
new file mode 100644
index 0000000..d49fee5
--- /dev/null
+++ b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.fixed
@@ -0,0 +1,27 @@
+// See https://github.com/rust-lang/rust/issues/88475
+//@ run-rustfix
+//@ edition:2021
+//@ check-pass
+#![warn(boxed_slice_into_iter)]
+#![allow(unused)]
+
+struct FooIter;
+
+trait MyIntoIter {
+    fn into_iter(self) -> FooIter;
+}
+
+impl<T> MyIntoIter for Box<[T]> {
+    fn into_iter(self) -> FooIter {
+        FooIter
+    }
+}
+
+struct Point;
+
+pub fn main() {
+    let points: Box<[_]> = vec![Point].into_boxed_slice();
+    let y = MyIntoIter::into_iter(points);
+    //~^ WARNING trait method `into_iter` will become ambiguous in Rust 2024
+    //~| WARNING this changes meaning in Rust 2024
+}
diff --git a/tests/ui/rust-2024/box-slice-into-iter-ambiguous.rs b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.rs
new file mode 100644
index 0000000..e78f550
--- /dev/null
+++ b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.rs
@@ -0,0 +1,27 @@
+// See https://github.com/rust-lang/rust/issues/88475
+//@ run-rustfix
+//@ edition:2021
+//@ check-pass
+#![warn(boxed_slice_into_iter)]
+#![allow(unused)]
+
+struct FooIter;
+
+trait MyIntoIter {
+    fn into_iter(self) -> FooIter;
+}
+
+impl<T> MyIntoIter for Box<[T]> {
+    fn into_iter(self) -> FooIter {
+        FooIter
+    }
+}
+
+struct Point;
+
+pub fn main() {
+    let points: Box<[_]> = vec![Point].into_boxed_slice();
+    let y = points.into_iter();
+    //~^ WARNING trait method `into_iter` will become ambiguous in Rust 2024
+    //~| WARNING this changes meaning in Rust 2024
+}
diff --git a/tests/ui/rust-2024/box-slice-into-iter-ambiguous.stderr b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.stderr
new file mode 100644
index 0000000..9cc79a7
--- /dev/null
+++ b/tests/ui/rust-2024/box-slice-into-iter-ambiguous.stderr
@@ -0,0 +1,15 @@
+warning: trait method `into_iter` will become ambiguous in Rust 2024
+  --> $DIR/box-slice-into-iter-ambiguous.rs:24:13
+   |
+LL |     let y = points.into_iter();
+   |             ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: `MyIntoIter::into_iter(points)`
+   |
+   = warning: this changes meaning in Rust 2024
+note: the lint level is defined here
+  --> $DIR/box-slice-into-iter-ambiguous.rs:5:9
+   |
+LL | #![warn(boxed_slice_into_iter)]
+   |         ^^^^^^^^^^^^^^^^^^^^^
+
+warning: 1 warning emitted
+
diff --git a/tests/ui/rust-2024/gen-kw-in-macro.rs b/tests/ui/rust-2024/gen-kw-in-macro.rs
new file mode 100644
index 0000000..3ccbe05
--- /dev/null
+++ b/tests/ui/rust-2024/gen-kw-in-macro.rs
@@ -0,0 +1,13 @@
+//@ check-pass
+
+#![deny(keyword_idents_2024)]
+
+macro_rules! foo {
+    ($gen:expr) => {
+        $gen
+    };
+}
+
+fn main() {
+    foo!(println!("hello, world"));
+}
diff --git a/tests/ui/rust-2024/gen-kw.e2015.stderr b/tests/ui/rust-2024/gen-kw.e2015.stderr
index b123631..b1074f7 100644
--- a/tests/ui/rust-2024/gen-kw.e2015.stderr
+++ b/tests/ui/rust-2024/gen-kw.e2015.stderr
@@ -22,5 +22,14 @@
    = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
-error: aborting due to 2 previous errors
+error: `gen` is a keyword in the 2024 edition
+  --> $DIR/gen-kw.rs:19:27
+   |
+LL |     () => { mod test { fn gen() {} } }
+   |                           ^^^ help: you can use a raw identifier to stay compatible: `r#gen`
+   |
+   = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/rust-2024/gen-kw.e2018.stderr b/tests/ui/rust-2024/gen-kw.e2018.stderr
index e10fc4c..b902cff 100644
--- a/tests/ui/rust-2024/gen-kw.e2018.stderr
+++ b/tests/ui/rust-2024/gen-kw.e2018.stderr
@@ -22,5 +22,14 @@
    = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
    = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
 
-error: aborting due to 2 previous errors
+error: `gen` is a keyword in the 2024 edition
+  --> $DIR/gen-kw.rs:19:27
+   |
+LL |     () => { mod test { fn gen() {} } }
+   |                           ^^^ help: you can use a raw identifier to stay compatible: `r#gen`
+   |
+   = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
+   = note: for more information, see issue #49716 <https://github.com/rust-lang/rust/issues/49716>
+
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/rust-2024/gen-kw.rs b/tests/ui/rust-2024/gen-kw.rs
index 3d2a3f9..04251cb 100644
--- a/tests/ui/rust-2024/gen-kw.rs
+++ b/tests/ui/rust-2024/gen-kw.rs
@@ -14,3 +14,12 @@
     //[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
     //[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
 }
+
+macro_rules! t {
+    () => { mod test { fn gen() {} } }
+    //~^ ERROR `gen` is a keyword in the 2024 edition
+    //[e2015]~| WARNING this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2024!
+    //[e2018]~| WARNING this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2024!
+}
+
+t!();
diff --git a/tests/ui/rustc-env/README.md b/tests/ui/rustc-env/README.md
new file mode 100644
index 0000000..ff674f3
--- /dev/null
+++ b/tests/ui/rustc-env/README.md
@@ -0,0 +1,6 @@
+Some environment variables affect rustc's behavior not because they are major compiler interfaces
+but rather because rustc is, ultimately, a Rust program, with debug logging, stack control, etc.
+
+Prefer to group tests that use environment variables to control something about rustc's core UX,
+like "can we parse this number of parens if we raise RUST_MIN_STACK?" with related code for that
+compiler feature.
diff --git a/tests/ui/auxiliary/rustc-rust-log-aux.rs b/tests/ui/rustc-env/auxiliary/rust-log-aux.rs
similarity index 100%
rename from tests/ui/auxiliary/rustc-rust-log-aux.rs
rename to tests/ui/rustc-env/auxiliary/rust-log-aux.rs
diff --git a/tests/ui/rustc-env/min-stack-banana.rs b/tests/ui/rustc-env/min-stack-banana.rs
new file mode 100644
index 0000000..abbb684
--- /dev/null
+++ b/tests/ui/rustc-env/min-stack-banana.rs
@@ -0,0 +1,2 @@
+//@ rustc-env:RUST_MIN_STACK=banana
+fn main() {}
diff --git a/tests/ui/rustc-env/min-stack-banana.stderr b/tests/ui/rustc-env/min-stack-banana.stderr
new file mode 100644
index 0000000..d379367
--- /dev/null
+++ b/tests/ui/rustc-env/min-stack-banana.stderr
@@ -0,0 +1,4 @@
+error: `RUST_MIN_STACK` should be a number of bytes, but was "banana"
+  |
+  = note: you can also unset `RUST_MIN_STACK` to use the default stack size
+
diff --git a/tests/ui/rustc-rust-log.rs b/tests/ui/rustc-env/rust-log.rs
similarity index 88%
rename from tests/ui/rustc-rust-log.rs
rename to tests/ui/rustc-env/rust-log.rs
index 299b6c4..1004075 100644
--- a/tests/ui/rustc-rust-log.rs
+++ b/tests/ui/rustc-env/rust-log.rs
@@ -5,7 +5,7 @@
 //@ dont-check-compiler-stdout
 //@ dont-check-compiler-stderr
 //@ compile-flags: --error-format human
-//@ aux-build: rustc-rust-log-aux.rs
+//@ aux-build: rust-log-aux.rs
 //@ rustc-env:RUSTC_LOG=debug
 
 fn main() {}
diff --git a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr
index 1006c3b..7f596a1 100644
--- a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr
+++ b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.aarch64.stderr
@@ -2,9 +2,5 @@
 
 error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`
 
-error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr
index 1006c3b..7f596a1 100644
--- a/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr
+++ b/tests/ui/sanitizer/cfi-is-incompatible-with-kcfi.x86_64.stderr
@@ -2,9 +2,5 @@
 
 error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`
 
-error: `-Zsanitizer=cfi` is incompatible with `-Zsanitizer=kcfi`
-   |
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
index 0b4c0a7..b00260f 100644
--- a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
+++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch-async.stderr
@@ -34,6 +34,11 @@
    |                  |               |
    |                  |               let's call the lifetime of this reference `'1`
    |                  lifetime `'a` defined here
+   |
+help: consider reusing a named lifetime parameter and update trait if needed
+   |
+LL |     async fn bar<'a>(self: Alias<&'a Self>, arg: &'a ()) -> &() { arg }
+   |                                   ++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs
index f1a3fb0..784afa8 100644
--- a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs
+++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.rs
@@ -3,17 +3,23 @@
 struct Foo;
 
 impl Foo {
-    fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
-    //~^ lifetime may not live long enough
+    fn a(self: Pin<&Foo>, f: &Foo) -> &Foo {
+        f //~ ERROR lifetime may not live long enough
+    }
 
-    fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
-    //~^ lifetime may not live long enough
+    // For this suggestion to be right, we'd need to also suggest `self: Pin<&'a Self>`, which we
+    // don't, but we provide a follow up suggestion to do so, so I condider that good at least for
+    // now.
+    fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) {
+        (self, f) //~ ERROR lifetime may not live long enough
+    }
 }
 
 type Alias<T> = Pin<T>;
 impl Foo {
-    fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
-    //~^ lifetime may not live long enough
+    fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() {
+        arg //~ ERROR lifetime may not live long enough
+    }
 }
 
 fn main() {}
diff --git a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr
index 209dae9..57527dd 100644
--- a/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr
+++ b/tests/ui/self/arbitrary_self_types_pin_lifetime_mismatch.stderr
@@ -1,38 +1,47 @@
 error: lifetime may not live long enough
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:6:46
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:7:9
    |
-LL |     fn a(self: Pin<&Foo>, f: &Foo) -> &Foo { f }
-   |                    -         -               ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
-   |                    |         |
-   |                    |         let's call the lifetime of this reference `'1`
+LL |     fn a(self: Pin<&Foo>, f: &Foo) -> &Foo {
+   |                    -         - let's call the lifetime of this reference `'1`
+   |                    |
    |                    let's call the lifetime of this reference `'2`
+LL |         f
+   |         ^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn a<'a>(self: Pin<&'a Foo>, f: &'a Foo) -> &Foo { f }
-   |         ++++            ++           ++
+LL |     fn a<'a>(self: Pin<&Foo>, f: &'a Foo) -> &'a Foo {
+   |         ++++                      ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:9:69
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:14:9
    |
-LL |     fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
-   |                    -          -                                     ^^^^^^^^^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
-   |                    |          |
-   |                    |          let's call the lifetime of this reference `'1`
+LL |     fn c(self: Pin<&Self>, f: &Foo, g: &Foo) -> (Pin<&Foo>, &Foo) {
+   |                    -          - let's call the lifetime of this reference `'1`
+   |                    |
    |                    let's call the lifetime of this reference `'2`
+LL |         (self, f)
+   |         ^^^^^^^^^ method was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1`
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn c<'a>(self: Pin<&'a Self>, f: &'a Foo, g: &Foo) -> (Pin<&Foo>, &Foo) { (self, f) }
-   |         ++++            ++            ++
+LL |     fn c<'a>(self: Pin<&Self>, f: &'a Foo, g: &Foo) -> (Pin<&'a Foo>, &'a Foo) {
+   |         ++++                       ++                        ++        ++
 
 error: lifetime may not live long enough
-  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:15:58
+  --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:21:9
    |
-LL |     fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg }
-   |            --  ---- has type `Pin<&'1 Foo>`              ^^^ method was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
+LL |     fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() {
+   |            --  ---- has type `Pin<&'1 Foo>`
    |            |
    |            lifetime `'a` defined here
+LL |         arg
+   |         ^^^ method was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a`
+   |
+help: consider reusing a named lifetime parameter and update trait if needed
+   |
+LL |     fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &'a () {
+   |                                                     ++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/self/elision/lt-ref-self-async.fixed b/tests/ui/self/elision/lt-ref-self-async.fixed
new file mode 100644
index 0000000..aa1d620
--- /dev/null
+++ b/tests/ui/self/elision/lt-ref-self-async.fixed
@@ -0,0 +1,47 @@
+//@ edition:2018
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
+
+use std::pin::Pin;
+
+struct Struct<'a> {
+    data: &'a u32,
+}
+
+impl<'a> Struct<'a> {
+    // Test using `&self` sugar:
+
+    async fn ref_self<'b>(&'b self, f: &'b u32) -> &u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    // Test using `&Self` explicitly:
+
+    async fn ref_Self<'b>(self: &'b Self, f: &'b u32) -> &u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    async fn box_ref_Self<'b>(self: Box<&'b Self>, f: &'b u32) -> &u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    async fn pin_ref_Self<'b>(self: Pin<&'b Self>, f: &'b u32) -> &u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    async fn box_box_ref_Self<'b>(self: Box<Box<&'b Self>>, f: &'b u32) -> &u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    async fn box_pin_Self<'b>(self: Box<Pin<&'b Self>>, f: &'b u32) -> &u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/elision/lt-ref-self-async.rs b/tests/ui/self/elision/lt-ref-self-async.rs
index 8eb4a48..38de0fd 100644
--- a/tests/ui/self/elision/lt-ref-self-async.rs
+++ b/tests/ui/self/elision/lt-ref-self-async.rs
@@ -1,10 +1,12 @@
 //@ edition:2018
-
-#![allow(non_snake_case)]
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
 
 use std::pin::Pin;
 
-struct Struct<'a> { data: &'a u32 }
+struct Struct<'a> {
+    data: &'a u32,
+}
 
 impl<'a> Struct<'a> {
     // Test using `&self` sugar:
@@ -42,4 +44,4 @@
     }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/self/elision/lt-ref-self-async.stderr b/tests/ui/self/elision/lt-ref-self-async.stderr
index 29d60ed..b84044f 100644
--- a/tests/ui/self/elision/lt-ref-self-async.stderr
+++ b/tests/ui/self/elision/lt-ref-self-async.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:13:9
+  --> $DIR/lt-ref-self-async.rs:15:9
    |
 LL |     async fn ref_self(&self, f: &u32) -> &u32 {
    |                       -         - let's call the lifetime of this reference `'1`
@@ -10,11 +10,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
+LL |     async fn ref_self<'b>(&'b self, f: &'b u32) -> &u32 {
    |                      ++++  ++           ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:20:9
+  --> $DIR/lt-ref-self-async.rs:22:9
    |
 LL |     async fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                             -         - let's call the lifetime of this reference `'1`
@@ -25,11 +25,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
+LL |     async fn ref_Self<'b>(self: &'b Self, f: &'b u32) -> &u32 {
    |                      ++++        ++           ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:25:9
+  --> $DIR/lt-ref-self-async.rs:27:9
    |
 LL |     async fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                                     -          - let's call the lifetime of this reference `'1`
@@ -40,11 +40,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
+LL |     async fn box_ref_Self<'b>(self: Box<&'b Self>, f: &'b u32) -> &u32 {
    |                          ++++            ++            ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:30:9
+  --> $DIR/lt-ref-self-async.rs:32:9
    |
 LL |     async fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                                     -          - let's call the lifetime of this reference `'1`
@@ -55,11 +55,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
+LL |     async fn pin_ref_Self<'b>(self: Pin<&'b Self>, f: &'b u32) -> &u32 {
    |                          ++++            ++            ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:35:9
+  --> $DIR/lt-ref-self-async.rs:37:9
    |
 LL |     async fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                             -           - let's call the lifetime of this reference `'1`
@@ -70,11 +70,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
+LL |     async fn box_box_ref_Self<'b>(self: Box<Box<&'b Self>>, f: &'b u32) -> &u32 {
    |                              ++++                ++             ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self-async.rs:40:9
+  --> $DIR/lt-ref-self-async.rs:42:9
    |
 LL |     async fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                         -           - let's call the lifetime of this reference `'1`
@@ -85,7 +85,7 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     async fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
+LL |     async fn box_pin_Self<'b>(self: Box<Pin<&'b Self>>, f: &'b u32) -> &u32 {
    |                          ++++                ++             ++
 
 error: aborting due to 6 previous errors
diff --git a/tests/ui/self/elision/lt-ref-self.fixed b/tests/ui/self/elision/lt-ref-self.fixed
new file mode 100644
index 0000000..1d90eac
--- /dev/null
+++ b/tests/ui/self/elision/lt-ref-self.fixed
@@ -0,0 +1,46 @@
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
+
+use std::pin::Pin;
+
+struct Struct<'a> {
+    data: &'a u32,
+}
+
+impl<'a> Struct<'a> {
+    // Test using `&self` sugar:
+
+    fn ref_self<'b>(&self, f: &'b u32) -> &'b u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    // Test using `&Self` explicitly:
+
+    fn ref_Self<'b>(self: &Self, f: &'b u32) -> &'b u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_ref_Self<'b>(self: Box<&Self>, f: &'b u32) -> &'b u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn pin_ref_Self<'b>(self: Pin<&Self>, f: &'b u32) -> &'b u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_box_ref_Self<'b>(self: Box<Box<&Self>>, f: &'b u32) -> &'b u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_pin_Self<'b>(self: Box<Pin<&Self>>, f: &'b u32) -> &'b u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/elision/lt-ref-self.rs b/tests/ui/self/elision/lt-ref-self.rs
index d37ed5a..4cd97c5 100644
--- a/tests/ui/self/elision/lt-ref-self.rs
+++ b/tests/ui/self/elision/lt-ref-self.rs
@@ -1,8 +1,11 @@
-#![allow(non_snake_case)]
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
 
 use std::pin::Pin;
 
-struct Struct<'a> { data: &'a u32 }
+struct Struct<'a> {
+    data: &'a u32,
+}
 
 impl<'a> Struct<'a> {
     // Test using `&self` sugar:
@@ -40,4 +43,4 @@
     }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/self/elision/lt-ref-self.stderr b/tests/ui/self/elision/lt-ref-self.stderr
index 216737a..5c8e0a7 100644
--- a/tests/ui/self/elision/lt-ref-self.stderr
+++ b/tests/ui/self/elision/lt-ref-self.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:11:9
+  --> $DIR/lt-ref-self.rs:14:9
    |
 LL |     fn ref_self(&self, f: &u32) -> &u32 {
    |                 -         - let's call the lifetime of this reference `'1`
@@ -10,11 +10,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
-   |                ++++  ++           ++
+LL |     fn ref_self<'b>(&self, f: &'b u32) -> &'b u32 {
+   |                ++++            ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:18:9
+  --> $DIR/lt-ref-self.rs:21:9
    |
 LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                       -         - let's call the lifetime of this reference `'1`
@@ -25,11 +25,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
-   |                ++++        ++           ++
+LL |     fn ref_Self<'b>(self: &Self, f: &'b u32) -> &'b u32 {
+   |                ++++                  ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:23:9
+  --> $DIR/lt-ref-self.rs:26:9
    |
 LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                               -          - let's call the lifetime of this reference `'1`
@@ -40,11 +40,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++            ++
+LL |     fn box_ref_Self<'b>(self: Box<&Self>, f: &'b u32) -> &'b u32 {
+   |                    ++++                       ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:28:9
+  --> $DIR/lt-ref-self.rs:31:9
    |
 LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                               -          - let's call the lifetime of this reference `'1`
@@ -55,11 +55,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++            ++
+LL |     fn pin_ref_Self<'b>(self: Pin<&Self>, f: &'b u32) -> &'b u32 {
+   |                    ++++                       ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:33:9
+  --> $DIR/lt-ref-self.rs:36:9
    |
 LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                       -           - let's call the lifetime of this reference `'1`
@@ -70,11 +70,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++             ++
+LL |     fn box_box_ref_Self<'b>(self: Box<Box<&Self>>, f: &'b u32) -> &'b u32 {
+   |                        ++++                            ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/lt-ref-self.rs:38:9
+  --> $DIR/lt-ref-self.rs:41:9
    |
 LL |     fn box_pin_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                   -           - let's call the lifetime of this reference `'1`
@@ -85,8 +85,8 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_pin_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
-   |                    ++++                ++             ++
+LL |     fn box_pin_Self<'b>(self: Box<Pin<&Self>>, f: &'b u32) -> &'b u32 {
+   |                    ++++                            ++          ++
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/self/elision/ref-mut-self.fixed b/tests/ui/self/elision/ref-mut-self.fixed
new file mode 100644
index 0000000..42e8050
--- /dev/null
+++ b/tests/ui/self/elision/ref-mut-self.fixed
@@ -0,0 +1,44 @@
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
+
+use std::pin::Pin;
+
+struct Struct {}
+
+impl Struct {
+    // Test using `&mut self` sugar:
+
+    fn ref_self<'a>(&mut self, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    // Test using `&mut Self` explicitly:
+
+    fn ref_Self<'a>(self: &mut Self, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_ref_Self<'a>(self: Box<&mut Self>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn pin_ref_Self<'a>(self: Pin<&mut Self>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_box_ref_Self<'a>(self: Box<Box<&mut Self>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_pin_ref_Self<'a>(self: Box<Pin<&mut Self>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/elision/ref-mut-self.rs b/tests/ui/self/elision/ref-mut-self.rs
index bb82e6b..87dab2a 100644
--- a/tests/ui/self/elision/ref-mut-self.rs
+++ b/tests/ui/self/elision/ref-mut-self.rs
@@ -1,8 +1,9 @@
-#![allow(non_snake_case)]
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
 
 use std::pin::Pin;
 
-struct Struct { }
+struct Struct {}
 
 impl Struct {
     // Test using `&mut self` sugar:
@@ -40,4 +41,4 @@
     }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/self/elision/ref-mut-self.stderr b/tests/ui/self/elision/ref-mut-self.stderr
index 12b64a3..620706f 100644
--- a/tests/ui/self/elision/ref-mut-self.stderr
+++ b/tests/ui/self/elision/ref-mut-self.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:11:9
+  --> $DIR/ref-mut-self.rs:12:9
    |
 LL |     fn ref_self(&mut self, f: &u32) -> &u32 {
    |                 -             - let's call the lifetime of this reference `'1`
@@ -10,11 +10,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_self<'a>(&'a mut self, f: &'a u32) -> &u32 {
-   |                ++++  ++               ++
+LL |     fn ref_self<'a>(&mut self, f: &'a u32) -> &'a u32 {
+   |                ++++                ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:18:9
+  --> $DIR/ref-mut-self.rs:19:9
    |
 LL |     fn ref_Self(self: &mut Self, f: &u32) -> &u32 {
    |                       -             - let's call the lifetime of this reference `'1`
@@ -25,11 +25,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_Self<'a>(self: &'a mut Self, f: &'a u32) -> &u32 {
-   |                ++++        ++               ++
+LL |     fn ref_Self<'a>(self: &mut Self, f: &'a u32) -> &'a u32 {
+   |                ++++                      ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:23:9
+  --> $DIR/ref-mut-self.rs:24:9
    |
 LL |     fn box_ref_Self(self: Box<&mut Self>, f: &u32) -> &u32 {
    |                               -              - let's call the lifetime of this reference `'1`
@@ -40,11 +40,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_ref_Self<'a>(self: Box<&'a mut Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++                ++
+LL |     fn box_ref_Self<'a>(self: Box<&mut Self>, f: &'a u32) -> &'a u32 {
+   |                    ++++                           ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:28:9
+  --> $DIR/ref-mut-self.rs:29:9
    |
 LL |     fn pin_ref_Self(self: Pin<&mut Self>, f: &u32) -> &u32 {
    |                               -              - let's call the lifetime of this reference `'1`
@@ -55,11 +55,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn pin_ref_Self<'a>(self: Pin<&'a mut Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++                ++
+LL |     fn pin_ref_Self<'a>(self: Pin<&mut Self>, f: &'a u32) -> &'a u32 {
+   |                    ++++                           ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:33:9
+  --> $DIR/ref-mut-self.rs:34:9
    |
 LL |     fn box_box_ref_Self(self: Box<Box<&mut Self>>, f: &u32) -> &u32 {
    |                                       -               - let's call the lifetime of this reference `'1`
@@ -70,11 +70,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_box_ref_Self<'a>(self: Box<Box<&'a mut Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++                 ++
+LL |     fn box_box_ref_Self<'a>(self: Box<Box<&mut Self>>, f: &'a u32) -> &'a u32 {
+   |                        ++++                                ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-self.rs:38:9
+  --> $DIR/ref-mut-self.rs:39:9
    |
 LL |     fn box_pin_ref_Self(self: Box<Pin<&mut Self>>, f: &u32) -> &u32 {
    |                                       -               - let's call the lifetime of this reference `'1`
@@ -85,8 +85,8 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_pin_ref_Self<'a>(self: Box<Pin<&'a mut Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++                 ++
+LL |     fn box_pin_ref_Self<'a>(self: Box<Pin<&mut Self>>, f: &'a u32) -> &'a u32 {
+   |                        ++++                                ++          ++
 
 error: aborting due to 6 previous errors
 
diff --git a/tests/ui/self/elision/ref-mut-struct.fixed b/tests/ui/self/elision/ref-mut-struct.fixed
new file mode 100644
index 0000000..f7a84d4
--- /dev/null
+++ b/tests/ui/self/elision/ref-mut-struct.fixed
@@ -0,0 +1,37 @@
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
+
+use std::pin::Pin;
+
+struct Struct {}
+
+impl Struct {
+    // Test using `&mut Struct` explicitly:
+
+    fn ref_Struct<'a>(self: &mut Struct, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_ref_Struct<'a>(self: Box<&mut Struct>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn pin_ref_Struct<'a>(self: Pin<&mut Struct>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_box_ref_Struct<'a>(self: Box<Box<&mut Struct>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_pin_ref_Struct<'a>(self: Box<Pin<&mut Struct>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/elision/ref-mut-struct.rs b/tests/ui/self/elision/ref-mut-struct.rs
index ca8bd8d..c227fa8 100644
--- a/tests/ui/self/elision/ref-mut-struct.rs
+++ b/tests/ui/self/elision/ref-mut-struct.rs
@@ -1,8 +1,9 @@
-#![allow(non_snake_case)]
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
 
 use std::pin::Pin;
 
-struct Struct { }
+struct Struct {}
 
 impl Struct {
     // Test using `&mut Struct` explicitly:
@@ -33,4 +34,4 @@
     }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/self/elision/ref-mut-struct.stderr b/tests/ui/self/elision/ref-mut-struct.stderr
index cde16ce..cce07f8 100644
--- a/tests/ui/self/elision/ref-mut-struct.stderr
+++ b/tests/ui/self/elision/ref-mut-struct.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:11:9
+  --> $DIR/ref-mut-struct.rs:12:9
    |
 LL |     fn ref_Struct(self: &mut Struct, f: &u32) -> &u32 {
    |                         -               - let's call the lifetime of this reference `'1`
@@ -10,11 +10,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_Struct<'a>(self: &'a mut Struct, f: &'a u32) -> &u32 {
-   |                  ++++        ++                 ++
+LL |     fn ref_Struct<'a>(self: &mut Struct, f: &'a u32) -> &'a u32 {
+   |                  ++++                        ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:16:9
+  --> $DIR/ref-mut-struct.rs:17:9
    |
 LL |     fn box_ref_Struct(self: Box<&mut Struct>, f: &u32) -> &u32 {
    |                                 -                - let's call the lifetime of this reference `'1`
@@ -25,11 +25,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_ref_Struct<'a>(self: Box<&'a mut Struct>, f: &'a u32) -> &u32 {
-   |                      ++++            ++                  ++
+LL |     fn box_ref_Struct<'a>(self: Box<&mut Struct>, f: &'a u32) -> &'a u32 {
+   |                      ++++                             ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:21:9
+  --> $DIR/ref-mut-struct.rs:22:9
    |
 LL |     fn pin_ref_Struct(self: Pin<&mut Struct>, f: &u32) -> &u32 {
    |                                 -                - let's call the lifetime of this reference `'1`
@@ -40,11 +40,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn pin_ref_Struct<'a>(self: Pin<&'a mut Struct>, f: &'a u32) -> &u32 {
-   |                      ++++            ++                  ++
+LL |     fn pin_ref_Struct<'a>(self: Pin<&mut Struct>, f: &'a u32) -> &'a u32 {
+   |                      ++++                             ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:26:9
+  --> $DIR/ref-mut-struct.rs:27:9
    |
 LL |     fn box_box_ref_Struct(self: Box<Box<&mut Struct>>, f: &u32) -> &u32 {
    |                                         -                 - let's call the lifetime of this reference `'1`
@@ -55,11 +55,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_box_ref_Struct<'a>(self: Box<Box<&'a mut Struct>>, f: &'a u32) -> &u32 {
-   |                          ++++                ++                   ++
+LL |     fn box_box_ref_Struct<'a>(self: Box<Box<&mut Struct>>, f: &'a u32) -> &'a u32 {
+   |                          ++++                                  ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-mut-struct.rs:31:9
+  --> $DIR/ref-mut-struct.rs:32:9
    |
 LL |     fn box_pin_ref_Struct(self: Box<Pin<&mut Struct>>, f: &u32) -> &u32 {
    |                                         -                 - let's call the lifetime of this reference `'1`
@@ -70,8 +70,8 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_pin_ref_Struct<'a>(self: Box<Pin<&'a mut Struct>>, f: &'a u32) -> &u32 {
-   |                          ++++                ++                   ++
+LL |     fn box_pin_ref_Struct<'a>(self: Box<Pin<&mut Struct>>, f: &'a u32) -> &'a u32 {
+   |                          ++++                                  ++          ++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/self/elision/ref-self.fixed b/tests/ui/self/elision/ref-self.fixed
new file mode 100644
index 0000000..8bf5a0b
--- /dev/null
+++ b/tests/ui/self/elision/ref-self.fixed
@@ -0,0 +1,61 @@
+//@ run-rustfix
+#![feature(arbitrary_self_types)]
+#![allow(non_snake_case, dead_code)]
+
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::pin::Pin;
+
+struct Struct {}
+
+struct Wrap<T, P>(T, PhantomData<P>);
+
+impl<T, P> Deref for Wrap<T, P> {
+    type Target = T;
+    fn deref(&self) -> &T {
+        &self.0
+    }
+}
+
+impl Struct {
+    // Test using `&self` sugar:
+
+    fn ref_self<'a>(&self, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    // Test using `&Self` explicitly:
+
+    fn ref_Self<'a>(self: &Self, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_ref_Self<'a>(self: Box<&Self>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn pin_ref_Self<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_box_ref_Self<'a>(self: Box<Box<&Self>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_pin_ref_Self<'a>(self: Box<Pin<&Self>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn wrap_ref_Self_Self<'a>(self: Wrap<&Self, Self>, f: &'a u8) -> &'a u8 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/elision/ref-self.rs b/tests/ui/self/elision/ref-self.rs
index dd07fe1..4b4b8aa 100644
--- a/tests/ui/self/elision/ref-self.rs
+++ b/tests/ui/self/elision/ref-self.rs
@@ -1,17 +1,20 @@
+//@ run-rustfix
 #![feature(arbitrary_self_types)]
-#![allow(non_snake_case)]
+#![allow(non_snake_case, dead_code)]
 
 use std::marker::PhantomData;
 use std::ops::Deref;
 use std::pin::Pin;
 
-struct Struct { }
+struct Struct {}
 
 struct Wrap<T, P>(T, PhantomData<P>);
 
 impl<T, P> Deref for Wrap<T, P> {
     type Target = T;
-    fn deref(&self) -> &T { &self.0 }
+    fn deref(&self) -> &T {
+        &self.0
+    }
 }
 
 impl Struct {
@@ -55,4 +58,4 @@
     }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/self/elision/ref-self.stderr b/tests/ui/self/elision/ref-self.stderr
index 3569325..c4ec8c5 100644
--- a/tests/ui/self/elision/ref-self.stderr
+++ b/tests/ui/self/elision/ref-self.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:21:9
+  --> $DIR/ref-self.rs:24:9
    |
 LL |     fn ref_self(&self, f: &u32) -> &u32 {
    |                 -         - let's call the lifetime of this reference `'1`
@@ -10,11 +10,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_self<'a>(&'a self, f: &'a u32) -> &u32 {
-   |                ++++  ++           ++
+LL |     fn ref_self<'a>(&self, f: &'a u32) -> &'a u32 {
+   |                ++++            ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:28:9
+  --> $DIR/ref-self.rs:31:9
    |
 LL |     fn ref_Self(self: &Self, f: &u32) -> &u32 {
    |                       -         - let's call the lifetime of this reference `'1`
@@ -25,11 +25,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_Self<'a>(self: &'a Self, f: &'a u32) -> &u32 {
-   |                ++++        ++           ++
+LL |     fn ref_Self<'a>(self: &Self, f: &'a u32) -> &'a u32 {
+   |                ++++                  ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:33:9
+  --> $DIR/ref-self.rs:36:9
    |
 LL |     fn box_ref_Self(self: Box<&Self>, f: &u32) -> &u32 {
    |                               -          - let's call the lifetime of this reference `'1`
@@ -40,11 +40,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_ref_Self<'a>(self: Box<&'a Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++            ++
+LL |     fn box_ref_Self<'a>(self: Box<&Self>, f: &'a u32) -> &'a u32 {
+   |                    ++++                       ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:38:9
+  --> $DIR/ref-self.rs:41:9
    |
 LL |     fn pin_ref_Self(self: Pin<&Self>, f: &u32) -> &u32 {
    |                               -          - let's call the lifetime of this reference `'1`
@@ -55,11 +55,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn pin_ref_Self<'a>(self: Pin<&'a Self>, f: &'a u32) -> &u32 {
-   |                    ++++            ++            ++
+LL |     fn pin_ref_Self<'a>(self: Pin<&Self>, f: &'a u32) -> &'a u32 {
+   |                    ++++                       ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:43:9
+  --> $DIR/ref-self.rs:46:9
    |
 LL |     fn box_box_ref_Self(self: Box<Box<&Self>>, f: &u32) -> &u32 {
    |                                       -           - let's call the lifetime of this reference `'1`
@@ -70,11 +70,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_box_ref_Self<'a>(self: Box<Box<&'a Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++             ++
+LL |     fn box_box_ref_Self<'a>(self: Box<Box<&Self>>, f: &'a u32) -> &'a u32 {
+   |                        ++++                            ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:48:9
+  --> $DIR/ref-self.rs:51:9
    |
 LL |     fn box_pin_ref_Self(self: Box<Pin<&Self>>, f: &u32) -> &u32 {
    |                                       -           - let's call the lifetime of this reference `'1`
@@ -85,11 +85,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_pin_ref_Self<'a>(self: Box<Pin<&'a Self>>, f: &'a u32) -> &u32 {
-   |                        ++++                ++             ++
+LL |     fn box_pin_ref_Self<'a>(self: Box<Pin<&Self>>, f: &'a u32) -> &'a u32 {
+   |                        ++++                            ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-self.rs:53:9
+  --> $DIR/ref-self.rs:56:9
    |
 LL |     fn wrap_ref_Self_Self(self: Wrap<&Self, Self>, f: &u8) -> &u8 {
    |                                      -                - let's call the lifetime of this reference `'1`
@@ -100,8 +100,8 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn wrap_ref_Self_Self<'a>(self: Wrap<&'a Self, Self>, f: &'a u8) -> &u8 {
-   |                          ++++             ++                  ++
+LL |     fn wrap_ref_Self_Self<'a>(self: Wrap<&Self, Self>, f: &'a u8) -> &'a u8 {
+   |                          ++++                              ++         ++
 
 error: aborting due to 7 previous errors
 
diff --git a/tests/ui/self/elision/ref-struct.fixed b/tests/ui/self/elision/ref-struct.fixed
new file mode 100644
index 0000000..411f601
--- /dev/null
+++ b/tests/ui/self/elision/ref-struct.fixed
@@ -0,0 +1,37 @@
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
+
+use std::pin::Pin;
+
+struct Struct {}
+
+impl Struct {
+    // Test using `&Struct` explicitly:
+
+    fn ref_Struct<'a>(self: &Struct, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_ref_Struct<'a>(self: Box<&Struct>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn pin_ref_Struct<'a>(self: Pin<&Struct>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_box_ref_Struct<'a>(self: Box<Box<&Struct>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+
+    fn box_pin_Struct<'a>(self: Box<Pin<&Struct>>, f: &'a u32) -> &'a u32 {
+        f
+        //~^ ERROR lifetime may not live long enough
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/self/elision/ref-struct.rs b/tests/ui/self/elision/ref-struct.rs
index 13a42cd..733a175 100644
--- a/tests/ui/self/elision/ref-struct.rs
+++ b/tests/ui/self/elision/ref-struct.rs
@@ -1,8 +1,9 @@
-#![allow(non_snake_case)]
+//@ run-rustfix
+#![allow(non_snake_case, dead_code)]
 
 use std::pin::Pin;
 
-struct Struct { }
+struct Struct {}
 
 impl Struct {
     // Test using `&Struct` explicitly:
@@ -33,4 +34,4 @@
     }
 }
 
-fn main() { }
+fn main() {}
diff --git a/tests/ui/self/elision/ref-struct.stderr b/tests/ui/self/elision/ref-struct.stderr
index a3d3ceb..860186c 100644
--- a/tests/ui/self/elision/ref-struct.stderr
+++ b/tests/ui/self/elision/ref-struct.stderr
@@ -1,5 +1,5 @@
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:11:9
+  --> $DIR/ref-struct.rs:12:9
    |
 LL |     fn ref_Struct(self: &Struct, f: &u32) -> &u32 {
    |                         -           - let's call the lifetime of this reference `'1`
@@ -10,11 +10,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn ref_Struct<'a>(self: &'a Struct, f: &'a u32) -> &u32 {
-   |                  ++++        ++             ++
+LL |     fn ref_Struct<'a>(self: &Struct, f: &'a u32) -> &'a u32 {
+   |                  ++++                    ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:16:9
+  --> $DIR/ref-struct.rs:17:9
    |
 LL |     fn box_ref_Struct(self: Box<&Struct>, f: &u32) -> &u32 {
    |                                 -            - let's call the lifetime of this reference `'1`
@@ -25,11 +25,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_ref_Struct<'a>(self: Box<&'a Struct>, f: &'a u32) -> &u32 {
-   |                      ++++            ++              ++
+LL |     fn box_ref_Struct<'a>(self: Box<&Struct>, f: &'a u32) -> &'a u32 {
+   |                      ++++                         ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:21:9
+  --> $DIR/ref-struct.rs:22:9
    |
 LL |     fn pin_ref_Struct(self: Pin<&Struct>, f: &u32) -> &u32 {
    |                                 -            - let's call the lifetime of this reference `'1`
@@ -40,11 +40,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn pin_ref_Struct<'a>(self: Pin<&'a Struct>, f: &'a u32) -> &u32 {
-   |                      ++++            ++              ++
+LL |     fn pin_ref_Struct<'a>(self: Pin<&Struct>, f: &'a u32) -> &'a u32 {
+   |                      ++++                         ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:26:9
+  --> $DIR/ref-struct.rs:27:9
    |
 LL |     fn box_box_ref_Struct(self: Box<Box<&Struct>>, f: &u32) -> &u32 {
    |                                         -             - let's call the lifetime of this reference `'1`
@@ -55,11 +55,11 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_box_ref_Struct<'a>(self: Box<Box<&'a Struct>>, f: &'a u32) -> &u32 {
-   |                          ++++                ++               ++
+LL |     fn box_box_ref_Struct<'a>(self: Box<Box<&Struct>>, f: &'a u32) -> &'a u32 {
+   |                          ++++                              ++          ++
 
 error: lifetime may not live long enough
-  --> $DIR/ref-struct.rs:31:9
+  --> $DIR/ref-struct.rs:32:9
    |
 LL |     fn box_pin_Struct(self: Box<Pin<&Struct>>, f: &u32) -> &u32 {
    |                                     -             - let's call the lifetime of this reference `'1`
@@ -70,8 +70,8 @@
    |
 help: consider introducing a named lifetime parameter and update trait if needed
    |
-LL |     fn box_pin_Struct<'a>(self: Box<Pin<&'a Struct>>, f: &'a u32) -> &u32 {
-   |                      ++++                ++               ++
+LL |     fn box_pin_Struct<'a>(self: Box<Pin<&Struct>>, f: &'a u32) -> &'a u32 {
+   |                      ++++                              ++          ++
 
 error: aborting due to 5 previous errors
 
diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs
index 4ad98d5..fc3087c 100644
--- a/tests/ui/simd/intrinsic/generic-arithmetic-2.rs
+++ b/tests/ui/simd/intrinsic/generic-arithmetic-2.rs
@@ -30,6 +30,7 @@
     fn simd_bswap<T>(x: T) -> T;
     fn simd_bitreverse<T>(x: T) -> T;
     fn simd_ctlz<T>(x: T) -> T;
+    fn simd_ctpop<T>(x: T) -> T;
     fn simd_cttz<T>(x: T) -> T;
 }
 
@@ -77,7 +78,6 @@
         simd_cttz(x);
         simd_cttz(y);
 
-
         simd_add(0, 0);
         //~^ ERROR expected SIMD input type, found non-SIMD `i32`
         simd_sub(0, 0);
@@ -108,24 +108,25 @@
         simd_cttz(0);
         //~^ ERROR expected SIMD input type, found non-SIMD `i32`
 
-
         simd_shl(z, z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_shr(z, z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_and(z, z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_or(z, z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_xor(z, z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_bswap(z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_bitreverse(z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_ctlz(z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
+        simd_ctpop(z);
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
         simd_cttz(z);
-//~^ ERROR unsupported operation on `f32x4` with element `f32`
+        //~^ ERROR unsupported operation on `f32x4` with element `f32`
     }
 }
diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr b/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr
index db26f34..6f5f86d 100644
--- a/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr
+++ b/tests/ui/simd/intrinsic/generic-arithmetic-2.stderr
@@ -83,59 +83,65 @@
    |         ^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shl` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:112:9
+  --> $DIR/generic-arithmetic-2.rs:111:9
    |
 LL |         simd_shl(z, z);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_shr` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:114:9
+  --> $DIR/generic-arithmetic-2.rs:113:9
    |
 LL |         simd_shr(z, z);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_and` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:116:9
+  --> $DIR/generic-arithmetic-2.rs:115:9
    |
 LL |         simd_and(z, z);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_or` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:118:9
+  --> $DIR/generic-arithmetic-2.rs:117:9
    |
 LL |         simd_or(z, z);
    |         ^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_xor` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:120:9
+  --> $DIR/generic-arithmetic-2.rs:119:9
    |
 LL |         simd_xor(z, z);
    |         ^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_bswap` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:122:9
+  --> $DIR/generic-arithmetic-2.rs:121:9
    |
 LL |         simd_bswap(z);
    |         ^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_bitreverse` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:124:9
+  --> $DIR/generic-arithmetic-2.rs:123:9
    |
 LL |         simd_bitreverse(z);
    |         ^^^^^^^^^^^^^^^^^^
 
 error[E0511]: invalid monomorphization of `simd_ctlz` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:126:9
+  --> $DIR/generic-arithmetic-2.rs:125:9
    |
 LL |         simd_ctlz(z);
    |         ^^^^^^^^^^^^
 
+error[E0511]: invalid monomorphization of `simd_ctpop` intrinsic: unsupported operation on `f32x4` with element `f32`
+  --> $DIR/generic-arithmetic-2.rs:127:9
+   |
+LL |         simd_ctpop(z);
+   |         ^^^^^^^^^^^^^
+
 error[E0511]: invalid monomorphization of `simd_cttz` intrinsic: unsupported operation on `f32x4` with element `f32`
-  --> $DIR/generic-arithmetic-2.rs:128:9
+  --> $DIR/generic-arithmetic-2.rs:129:9
    |
 LL |         simd_cttz(z);
    |         ^^^^^^^^^^^^
 
-error: aborting due to 23 previous errors
+error: aborting due to 24 previous errors
 
 For more information about this error, try `rustc --explain E0511`.
diff --git a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
index 33143b1..60dfa62 100644
--- a/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
+++ b/tests/ui/simd/intrinsic/generic-arithmetic-pass.rs
@@ -47,6 +47,7 @@
     fn simd_bswap<T>(x: T) -> T;
     fn simd_bitreverse<T>(x: T) -> T;
     fn simd_ctlz<T>(x: T) -> T;
+    fn simd_ctpop<T>(x: T) -> T;
     fn simd_cttz<T>(x: T) -> T;
 }
 
@@ -57,6 +58,8 @@
     let x2 = i32x4(2, 3, 4, 5);
     let y2 = U32::<4>([2, 3, 4, 5]);
     let z2 = f32x4(2.0, 3.0, 4.0, 5.0);
+    let x3 = i32x4(0, i32::MAX, i32::MIN, -1_i32);
+    let y3 = U32::<4>([0, i32::MAX as _, i32::MIN as _, -1_i32 as _]);
 
     unsafe {
         all_eq!(simd_add(x1, x2), i32x4(3, 5, 7, 9));
@@ -147,6 +150,13 @@
         all_eq!(simd_ctlz(x1), i32x4(31, 30, 30, 29));
         all_eq_!(simd_ctlz(y1), U32::<4>([31, 30, 30, 29]));
 
+        all_eq!(simd_ctpop(x1), i32x4(1, 1, 2, 1));
+        all_eq_!(simd_ctpop(y1), U32::<4>([1, 1, 2, 1]));
+        all_eq!(simd_ctpop(x2), i32x4(1, 2, 1, 2));
+        all_eq_!(simd_ctpop(y2), U32::<4>([1, 2, 1, 2]));
+        all_eq!(simd_ctpop(x3), i32x4(0, 31, 1, 32));
+        all_eq_!(simd_ctpop(y3), U32::<4>([0, 31, 1, 32]));
+
         all_eq!(simd_cttz(x1), i32x4(0, 1, 0, 2));
         all_eq_!(simd_cttz(y1), U32::<4>([0, 1, 0, 2]));
     }
diff --git a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
index 8df0613..99f8dbd 100644
--- a/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
+++ b/tests/ui/sized/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.stderr
@@ -25,8 +25,8 @@
    |
 
 error[E0533]: expected unit struct, unit variant or constant, found associated function `str<{
-                      fn str() { let (/*ERROR*/); }
-                  }, T>::as_bytes`
+                  fn str() { let (/*ERROR*/); }
+              }, T>::as_bytes`
   --> $DIR/ensure-overriding-bindings-in-pattern-with-ty-err-doesnt-ice.rs:2:9
    |
 LL |     let str::<{fn str() { let str::T>>::as_bytes; }}, T>::as_bytes;
diff --git a/tests/ui/span/macro-ty-params.rs b/tests/ui/span/macro-ty-params.rs
index cf28b02..c7ce9b9 100644
--- a/tests/ui/span/macro-ty-params.rs
+++ b/tests/ui/span/macro-ty-params.rs
@@ -11,5 +11,4 @@
     foo::<>!(); //~ ERROR generic arguments in macro path
     m!(Default<>);
     //~^ ERROR unexpected generic arguments in path
-    //~^^ ERROR generic arguments in macro path
 }
diff --git a/tests/ui/span/macro-ty-params.stderr b/tests/ui/span/macro-ty-params.stderr
index 7023ef8..138cd25 100644
--- a/tests/ui/span/macro-ty-params.stderr
+++ b/tests/ui/span/macro-ty-params.stderr
@@ -16,11 +16,5 @@
 LL |     m!(Default<>);
    |               ^^
 
-error: generic arguments in macro path
-  --> $DIR/macro-ty-params.rs:12:15
-   |
-LL |     m!(Default<>);
-   |               ^^
-
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
diff --git a/tests/ui/span/multispan-import-lint.stderr b/tests/ui/span/multispan-import-lint.stderr
index 4a955d1..a4ea1af 100644
--- a/tests/ui/span/multispan-import-lint.stderr
+++ b/tests/ui/span/multispan-import-lint.stderr
@@ -1,4 +1,4 @@
-warning: unused imports: `Eq`, `Ord`, `PartialEq`, `PartialOrd`
+warning: unused imports: `Eq`, `Ord`, `PartialEq`, and `PartialOrd`
   --> $DIR/multispan-import-lint.rs:5:16
    |
 LL | use std::cmp::{Eq, Ord, min, PartialEq, PartialOrd};
diff --git a/tests/ui/auxiliary/check_static_recursion_foreign_helper.rs b/tests/ui/statics/auxiliary/check_static_recursion_foreign_helper.rs
similarity index 100%
rename from tests/ui/auxiliary/check_static_recursion_foreign_helper.rs
rename to tests/ui/statics/auxiliary/check_static_recursion_foreign_helper.rs
diff --git a/tests/ui/check-static-immutable-mut-slices.rs b/tests/ui/statics/check-immutable-mut-slices.rs
similarity index 100%
rename from tests/ui/check-static-immutable-mut-slices.rs
rename to tests/ui/statics/check-immutable-mut-slices.rs
diff --git a/tests/ui/check-static-immutable-mut-slices.stderr b/tests/ui/statics/check-immutable-mut-slices.stderr
similarity index 84%
rename from tests/ui/check-static-immutable-mut-slices.stderr
rename to tests/ui/statics/check-immutable-mut-slices.stderr
index 402f903..5cb35a7 100644
--- a/tests/ui/check-static-immutable-mut-slices.stderr
+++ b/tests/ui/statics/check-immutable-mut-slices.stderr
@@ -1,5 +1,5 @@
 error[E0764]: mutable references are not allowed in the final value of statics
-  --> $DIR/check-static-immutable-mut-slices.rs:3:37
+  --> $DIR/check-immutable-mut-slices.rs:3:37
    |
 LL | static TEST: &'static mut [isize] = &mut [];
    |                                     ^^^^^^^
diff --git a/tests/ui/check-static-recursion-foreign.rs b/tests/ui/statics/check-recursion-foreign.rs
similarity index 100%
rename from tests/ui/check-static-recursion-foreign.rs
rename to tests/ui/statics/check-recursion-foreign.rs
diff --git a/tests/ui/check-static-values-constraints.rs b/tests/ui/statics/check-values-constraints.rs
similarity index 100%
rename from tests/ui/check-static-values-constraints.rs
rename to tests/ui/statics/check-values-constraints.rs
diff --git a/tests/ui/check-static-values-constraints.stderr b/tests/ui/statics/check-values-constraints.stderr
similarity index 88%
rename from tests/ui/check-static-values-constraints.stderr
rename to tests/ui/statics/check-values-constraints.stderr
index fe5f2a3..45a699f 100644
--- a/tests/ui/check-static-values-constraints.stderr
+++ b/tests/ui/statics/check-values-constraints.stderr
@@ -1,5 +1,5 @@
 error[E0493]: destructor of `SafeStruct` cannot be evaluated at compile-time
-  --> $DIR/check-static-values-constraints.rs:64:7
+  --> $DIR/check-values-constraints.rs:64:7
    |
 LL |       ..SafeStruct {
    |  _______^
@@ -12,7 +12,7 @@
    |   - value is dropped here
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:81:33
+  --> $DIR/check-values-constraints.rs:81:33
    |
 LL | static STATIC11: Vec<MyOwned> = vec![MyOwned];
    |                                 ^^^^^^^^^^^^^ allocation not allowed in statics
@@ -20,7 +20,7 @@
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
-  --> $DIR/check-static-values-constraints.rs:81:33
+  --> $DIR/check-values-constraints.rs:81:33
    |
 LL | static STATIC11: Vec<MyOwned> = vec![MyOwned];
    |                                 ^^^^^^^^^^^^^
@@ -30,7 +30,7 @@
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `<str as ToString>::to_string` in statics
-  --> $DIR/check-static-values-constraints.rs:92:38
+  --> $DIR/check-values-constraints.rs:92:38
    |
 LL |     field2: SafeEnum::Variant4("str".to_string()),
    |                                      ^^^^^^^^^^^
@@ -43,7 +43,7 @@
    |
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:96:5
+  --> $DIR/check-values-constraints.rs:96:5
    |
 LL |     vec![MyOwned],
    |     ^^^^^^^^^^^^^ allocation not allowed in statics
@@ -51,7 +51,7 @@
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
-  --> $DIR/check-static-values-constraints.rs:96:5
+  --> $DIR/check-values-constraints.rs:96:5
    |
 LL |     vec![MyOwned],
    |     ^^^^^^^^^^^^^
@@ -61,7 +61,7 @@
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:98:5
+  --> $DIR/check-values-constraints.rs:98:5
    |
 LL |     vec![MyOwned],
    |     ^^^^^^^^^^^^^ allocation not allowed in statics
@@ -69,7 +69,7 @@
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
-  --> $DIR/check-static-values-constraints.rs:98:5
+  --> $DIR/check-values-constraints.rs:98:5
    |
 LL |     vec![MyOwned],
    |     ^^^^^^^^^^^^^
@@ -79,7 +79,7 @@
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:103:6
+  --> $DIR/check-values-constraints.rs:103:6
    |
 LL |     &vec![MyOwned],
    |      ^^^^^^^^^^^^^ allocation not allowed in statics
@@ -87,7 +87,7 @@
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
-  --> $DIR/check-static-values-constraints.rs:103:6
+  --> $DIR/check-values-constraints.rs:103:6
    |
 LL |     &vec![MyOwned],
    |      ^^^^^^^^^^^^^
@@ -97,7 +97,7 @@
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:105:6
+  --> $DIR/check-values-constraints.rs:105:6
    |
 LL |     &vec![MyOwned],
    |      ^^^^^^^^^^^^^ allocation not allowed in statics
@@ -105,7 +105,7 @@
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `slice::<impl [MyOwned]>::into_vec::<std::alloc::Global>` in statics
-  --> $DIR/check-static-values-constraints.rs:105:6
+  --> $DIR/check-values-constraints.rs:105:6
    |
 LL |     &vec![MyOwned],
    |      ^^^^^^^^^^^^^
@@ -115,7 +115,7 @@
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:111:31
+  --> $DIR/check-values-constraints.rs:111:31
    |
 LL | static STATIC19: Vec<isize> = vec![3];
    |                               ^^^^^^^ allocation not allowed in statics
@@ -123,7 +123,7 @@
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `slice::<impl [isize]>::into_vec::<std::alloc::Global>` in statics
-  --> $DIR/check-static-values-constraints.rs:111:31
+  --> $DIR/check-values-constraints.rs:111:31
    |
 LL | static STATIC19: Vec<isize> = vec![3];
    |                               ^^^^^^^
@@ -133,7 +133,7 @@
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0010]: allocations are not allowed in statics
-  --> $DIR/check-static-values-constraints.rs:117:32
+  --> $DIR/check-values-constraints.rs:117:32
    |
 LL |         static x: Vec<isize> = vec![3];
    |                                ^^^^^^^ allocation not allowed in statics
@@ -141,7 +141,7 @@
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0015]: cannot call non-const fn `slice::<impl [isize]>::into_vec::<std::alloc::Global>` in statics
-  --> $DIR/check-static-values-constraints.rs:117:32
+  --> $DIR/check-values-constraints.rs:117:32
    |
 LL |         static x: Vec<isize> = vec![3];
    |                                ^^^^^^^
@@ -151,7 +151,7 @@
    = note: this error originates in the macro `vec` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0507]: cannot move out of static item `x`
-  --> $DIR/check-static-values-constraints.rs:119:9
+  --> $DIR/check-values-constraints.rs:119:9
    |
 LL |         x
    |         ^ move occurs because `x` has type `Vec<isize>`, which does not implement the `Copy` trait
diff --git a/tests/crashes/113272.rs b/tests/ui/structs/ice-struct-tail-normalization-113272.rs
similarity index 66%
rename from tests/crashes/113272.rs
rename to tests/ui/structs/ice-struct-tail-normalization-113272.rs
index d161575..85d3d1b 100644
--- a/tests/crashes/113272.rs
+++ b/tests/ui/structs/ice-struct-tail-normalization-113272.rs
@@ -1,9 +1,10 @@
-//@ known-bug: #113272
 trait Trait {
     type RefTarget;
 }
 
 impl Trait for () where Missing: Trait {}
+//~^ ERROR cannot find type `Missing` in this scope
+//~| ERROR not all trait items implemented, missing: `RefTarget`
 
 struct Other {
     data: <() as Trait>::RefTarget,
diff --git a/tests/ui/structs/ice-struct-tail-normalization-113272.stderr b/tests/ui/structs/ice-struct-tail-normalization-113272.stderr
new file mode 100644
index 0000000..a205eb8
--- /dev/null
+++ b/tests/ui/structs/ice-struct-tail-normalization-113272.stderr
@@ -0,0 +1,19 @@
+error[E0412]: cannot find type `Missing` in this scope
+  --> $DIR/ice-struct-tail-normalization-113272.rs:5:25
+   |
+LL | impl Trait for () where Missing: Trait {}
+   |                         ^^^^^^^ not found in this scope
+
+error[E0046]: not all trait items implemented, missing: `RefTarget`
+  --> $DIR/ice-struct-tail-normalization-113272.rs:5:1
+   |
+LL |     type RefTarget;
+   |     -------------- `RefTarget` from trait
+...
+LL | impl Trait for () where Missing: Trait {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `RefTarget` in implementation
+
+error: aborting due to 2 previous errors
+
+Some errors have detailed explanations: E0046, E0412.
+For more information about an error, try `rustc --explain E0046`.
diff --git a/tests/ui/dont-suggest-private-trait-method.rs b/tests/ui/suggestions/dont-suggest-private-trait-method.rs
similarity index 100%
rename from tests/ui/dont-suggest-private-trait-method.rs
rename to tests/ui/suggestions/dont-suggest-private-trait-method.rs
diff --git a/tests/ui/dont-suggest-private-trait-method.stderr b/tests/ui/suggestions/dont-suggest-private-trait-method.stderr
similarity index 100%
rename from tests/ui/dont-suggest-private-trait-method.stderr
rename to tests/ui/suggestions/dont-suggest-private-trait-method.stderr
diff --git a/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr b/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr
index fee83eb..e068fdb 100644
--- a/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr
+++ b/tests/ui/suggestions/recover-from-semicolon-trailing-item.stderr
@@ -3,6 +3,8 @@
    |
 LL | mod M {};
    |         ^ help: remove this semicolon
+   |
+   = help: module declarations are not followed by a semicolon
 
 error: expected item, found `;`
   --> $DIR/recover-from-semicolon-trailing-item.rs:4:12
@@ -17,6 +19,8 @@
    |
 LL | fn foo(a: usize) {};
    |                    ^ help: remove this semicolon
+   |
+   = help: function declarations are not followed by a semicolon
 
 error[E0308]: mismatched types
   --> $DIR/recover-from-semicolon-trailing-item.rs:10:20
diff --git a/tests/ui/suggest-null-ptr.fixed b/tests/ui/suggestions/suggest-null-ptr.fixed
similarity index 100%
rename from tests/ui/suggest-null-ptr.fixed
rename to tests/ui/suggestions/suggest-null-ptr.fixed
diff --git a/tests/ui/suggest-null-ptr.rs b/tests/ui/suggestions/suggest-null-ptr.rs
similarity index 100%
rename from tests/ui/suggest-null-ptr.rs
rename to tests/ui/suggestions/suggest-null-ptr.rs
diff --git a/tests/ui/suggest-null-ptr.stderr b/tests/ui/suggestions/suggest-null-ptr.stderr
similarity index 100%
rename from tests/ui/suggest-null-ptr.stderr
rename to tests/ui/suggestions/suggest-null-ptr.stderr
diff --git a/tests/ui/trait-impl-bound-suggestions.fixed b/tests/ui/suggestions/trait-impl-bound-suggestions.fixed
similarity index 100%
rename from tests/ui/trait-impl-bound-suggestions.fixed
rename to tests/ui/suggestions/trait-impl-bound-suggestions.fixed
diff --git a/tests/ui/trait-impl-bound-suggestions.rs b/tests/ui/suggestions/trait-impl-bound-suggestions.rs
similarity index 100%
rename from tests/ui/trait-impl-bound-suggestions.rs
rename to tests/ui/suggestions/trait-impl-bound-suggestions.rs
diff --git a/tests/ui/trait-impl-bound-suggestions.stderr b/tests/ui/suggestions/trait-impl-bound-suggestions.stderr
similarity index 100%
rename from tests/ui/trait-impl-bound-suggestions.stderr
rename to tests/ui/suggestions/trait-impl-bound-suggestions.stderr
diff --git a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs
index f882a15..35a06d3 100644
--- a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs
+++ b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs
@@ -3,6 +3,7 @@
 
 fn main() -> Result<(), ()> {
     a(|| {
+        //~^ HELP: try adding a return type
         b()
         //~^ ERROR: mismatched types [E0308]
         //~| NOTE: expected `()`, found `i32`
diff --git a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr
index 9392854..5506456a 100644
--- a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr
+++ b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr
@@ -1,13 +1,20 @@
 error[E0308]: mismatched types
-  --> $DIR/try-operator-dont-suggest-semicolon.rs:6:9
+  --> $DIR/try-operator-dont-suggest-semicolon.rs:7:9
    |
 LL |         b()
-   |         ^^^- help: consider using a semicolon here: `;`
-   |         |
-   |         expected `()`, found `i32`
+   |         ^^^ expected `()`, found `i32`
+   |
+help: consider using a semicolon here
+   |
+LL |         b();
+   |            +
+help: try adding a return type
+   |
+LL |     a(|| -> i32 {
+   |          ++++++
 
 error[E0308]: mismatched types
-  --> $DIR/try-operator-dont-suggest-semicolon.rs:16:9
+  --> $DIR/try-operator-dont-suggest-semicolon.rs:17:9
    |
 LL | /     if true {
 LL | |
diff --git a/tests/ui/suggestions/unused-imports.fixed b/tests/ui/suggestions/unused-imports.fixed
new file mode 100644
index 0000000..57dd091
--- /dev/null
+++ b/tests/ui/suggestions/unused-imports.fixed
@@ -0,0 +1,35 @@
+//@ run-rustfix
+//@ check-pass
+
+#![warn(unused_imports)]
+
+pub mod nested {
+    pub struct A;
+    pub struct B;
+    pub struct C;
+    pub struct D;
+    pub mod even_more {
+        pub struct E;
+        pub struct F;
+        pub struct G;
+    }
+    pub mod another {
+        pub struct H;
+        pub struct I;
+    }
+}
+
+use nested::B;
+//~^ WARN unused import
+
+use nested::even_more::F;
+//~^^^^^^^ WARN unused import
+
+// Note that the following fix should result in `::{self}`, not `::self`. The latter is invalid
+// Rust syntax, so the braces should not be removed.
+use nested::another::{self};
+//~^ WARN unused import
+
+fn main() {
+    let _ = (B, F, another::I);
+}
diff --git a/tests/ui/suggestions/unused-imports.rs b/tests/ui/suggestions/unused-imports.rs
new file mode 100644
index 0000000..5f9dd24
--- /dev/null
+++ b/tests/ui/suggestions/unused-imports.rs
@@ -0,0 +1,42 @@
+//@ run-rustfix
+//@ check-pass
+
+#![warn(unused_imports)]
+
+pub mod nested {
+    pub struct A;
+    pub struct B;
+    pub struct C;
+    pub struct D;
+    pub mod even_more {
+        pub struct E;
+        pub struct F;
+        pub struct G;
+    }
+    pub mod another {
+        pub struct H;
+        pub struct I;
+    }
+}
+
+use nested::{A, B, C};
+//~^ WARN unused import
+
+use nested::{
+    D,
+    even_more::{
+        E,
+        F,
+        G,
+                         },
+            };
+//~^^^^^^^ WARN unused import
+
+// Note that the following fix should result in `::{self}`, not `::self`. The latter is invalid
+// Rust syntax, so the braces should not be removed.
+use nested::another::{self, I};
+//~^ WARN unused import
+
+fn main() {
+    let _ = (B, F, another::I);
+}
diff --git a/tests/ui/suggestions/unused-imports.stderr b/tests/ui/suggestions/unused-imports.stderr
new file mode 100644
index 0000000..31edb4e
--- /dev/null
+++ b/tests/ui/suggestions/unused-imports.stderr
@@ -0,0 +1,32 @@
+warning: unused imports: `A` and `C`
+  --> $DIR/unused-imports.rs:22:14
+   |
+LL | use nested::{A, B, C};
+   |              ^     ^
+   |
+note: the lint level is defined here
+  --> $DIR/unused-imports.rs:4:9
+   |
+LL | #![warn(unused_imports)]
+   |         ^^^^^^^^^^^^^^
+
+warning: unused imports: `D`, `E`, and `G`
+  --> $DIR/unused-imports.rs:26:5
+   |
+LL |     D,
+   |     ^
+LL |     even_more::{
+LL |         E,
+   |         ^
+LL |         F,
+LL |         G,
+   |         ^
+
+warning: unused import: `I`
+  --> $DIR/unused-imports.rs:37:29
+   |
+LL | use nested::another::{self, I};
+   |                             ^
+
+warning: 3 warnings emitted
+
diff --git a/tests/ui/symbol-names/types.legacy.stderr b/tests/ui/symbol-names/types.legacy.stderr
index a4984d5..87c3aca 100644
--- a/tests/ui/symbol-names/types.legacy.stderr
+++ b/tests/ui/symbol-names/types.legacy.stderr
@@ -1,470 +1,506 @@
 error: symbol-name(_ZN1a1b16Type$LT$bool$GT$17h[HASH]E)
-  --> $DIR/types.rs:13:5
+  --> $DIR/types.rs:18:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<bool>::h[HASH])
-  --> $DIR/types.rs:13:5
+  --> $DIR/types.rs:18:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<bool>)
-  --> $DIR/types.rs:13:5
+  --> $DIR/types.rs:18:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b16Type$LT$char$GT$17h[HASH]E)
-  --> $DIR/types.rs:19:5
+  --> $DIR/types.rs:27:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<char>::h[HASH])
-  --> $DIR/types.rs:19:5
+  --> $DIR/types.rs:27:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<char>)
-  --> $DIR/types.rs:19:5
+  --> $DIR/types.rs:27:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b14Type$LT$i8$GT$17h[HASH]E)
-  --> $DIR/types.rs:25:5
+  --> $DIR/types.rs:36:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i8>::h[HASH])
-  --> $DIR/types.rs:25:5
+  --> $DIR/types.rs:36:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i8>)
-  --> $DIR/types.rs:25:5
+  --> $DIR/types.rs:36:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i16$GT$17h[HASH]E)
-  --> $DIR/types.rs:31:5
+  --> $DIR/types.rs:45:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i16>::h[HASH])
-  --> $DIR/types.rs:31:5
+  --> $DIR/types.rs:45:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i16>)
-  --> $DIR/types.rs:31:5
+  --> $DIR/types.rs:45:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i32$GT$17h[HASH]E)
-  --> $DIR/types.rs:37:5
+  --> $DIR/types.rs:54:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i32>::h[HASH])
-  --> $DIR/types.rs:37:5
+  --> $DIR/types.rs:54:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i32>)
-  --> $DIR/types.rs:37:5
+  --> $DIR/types.rs:54:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i64$GT$17h[HASH]E)
-  --> $DIR/types.rs:43:5
+  --> $DIR/types.rs:63:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i64>::h[HASH])
-  --> $DIR/types.rs:43:5
+  --> $DIR/types.rs:63:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i64>)
-  --> $DIR/types.rs:43:5
+  --> $DIR/types.rs:63:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b14Type$LT$u8$GT$17h[HASH]E)
-  --> $DIR/types.rs:49:5
+  --> $DIR/types.rs:72:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u8>::h[HASH])
-  --> $DIR/types.rs:49:5
+  --> $DIR/types.rs:72:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u8>)
-  --> $DIR/types.rs:49:5
+  --> $DIR/types.rs:72:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u16$GT$17h[HASH]E)
-  --> $DIR/types.rs:55:5
+  --> $DIR/types.rs:81:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u16>::h[HASH])
-  --> $DIR/types.rs:55:5
+  --> $DIR/types.rs:81:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u16>)
-  --> $DIR/types.rs:55:5
+  --> $DIR/types.rs:81:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u32$GT$17h[HASH]E)
-  --> $DIR/types.rs:61:5
+  --> $DIR/types.rs:90:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u32>::h[HASH])
-  --> $DIR/types.rs:61:5
+  --> $DIR/types.rs:90:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u32>)
-  --> $DIR/types.rs:61:5
+  --> $DIR/types.rs:90:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u64$GT$17h[HASH]E)
-  --> $DIR/types.rs:67:5
+  --> $DIR/types.rs:99:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u64>::h[HASH])
-  --> $DIR/types.rs:67:5
+  --> $DIR/types.rs:99:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u64>)
-  --> $DIR/types.rs:67:5
+  --> $DIR/types.rs:99:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_ZN1a1b15Type$LT$f16$GT$17h[HASH]E)
+  --> $DIR/types.rs:108:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(a::b::Type<f16>::h[HASH])
+  --> $DIR/types.rs:108:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(a::b::Type<f16>)
+  --> $DIR/types.rs:108:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f32$GT$17h[HASH]E)
-  --> $DIR/types.rs:73:5
+  --> $DIR/types.rs:117:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f32>::h[HASH])
-  --> $DIR/types.rs:73:5
+  --> $DIR/types.rs:117:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f32>)
-  --> $DIR/types.rs:73:5
+  --> $DIR/types.rs:117:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f64$GT$17h[HASH]E)
-  --> $DIR/types.rs:79:5
+  --> $DIR/types.rs:126:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f64>::h[HASH])
-  --> $DIR/types.rs:79:5
+  --> $DIR/types.rs:126:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f64>)
-  --> $DIR/types.rs:79:5
+  --> $DIR/types.rs:126:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_ZN1a1b16Type$LT$f128$GT$17h[HASH]E)
+  --> $DIR/types.rs:135:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(a::b::Type<f128>::h[HASH])
+  --> $DIR/types.rs:135:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(a::b::Type<f128>)
+  --> $DIR/types.rs:135:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$str$GT$17h[HASH]E)
-  --> $DIR/types.rs:85:5
+  --> $DIR/types.rs:144:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<str>::h[HASH])
-  --> $DIR/types.rs:85:5
+  --> $DIR/types.rs:144:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<str>)
-  --> $DIR/types.rs:85:5
+  --> $DIR/types.rs:144:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b17Type$LT$$u21$$GT$17h[HASH]E)
-  --> $DIR/types.rs:91:5
+  --> $DIR/types.rs:153:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<!>::h[HASH])
-  --> $DIR/types.rs:91:5
+  --> $DIR/types.rs:153:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<!>)
-  --> $DIR/types.rs:91:5
+  --> $DIR/types.rs:153:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b20Type$LT$$LP$$RP$$GT$17h[HASH]E)
-  --> $DIR/types.rs:97:5
+  --> $DIR/types.rs:162:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<()>::h[HASH])
-  --> $DIR/types.rs:97:5
+  --> $DIR/types.rs:162:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<()>)
-  --> $DIR/types.rs:97:5
+  --> $DIR/types.rs:162:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b25Type$LT$$LP$u8$C$$RP$$GT$17h[HASH]E)
-  --> $DIR/types.rs:103:5
+  --> $DIR/types.rs:171:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,)>::h[HASH])
-  --> $DIR/types.rs:103:5
+  --> $DIR/types.rs:171:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,)>)
-  --> $DIR/types.rs:103:5
+  --> $DIR/types.rs:171:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b28Type$LT$$LP$u8$C$u16$RP$$GT$17h[HASH]E)
-  --> $DIR/types.rs:109:5
+  --> $DIR/types.rs:180:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,u16)>::h[HASH])
-  --> $DIR/types.rs:109:5
+  --> $DIR/types.rs:180:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,u16)>)
-  --> $DIR/types.rs:109:5
+  --> $DIR/types.rs:180:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b34Type$LT$$LP$u8$C$u16$C$u32$RP$$GT$17h[HASH]E)
-  --> $DIR/types.rs:115:5
+  --> $DIR/types.rs:189:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,u16,u32)>::h[HASH])
-  --> $DIR/types.rs:115:5
+  --> $DIR/types.rs:189:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,u16,u32)>)
-  --> $DIR/types.rs:115:5
+  --> $DIR/types.rs:189:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b28Type$LT$$BP$const$u20$u8$GT$17h[HASH]E)
-  --> $DIR/types.rs:121:5
+  --> $DIR/types.rs:198:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<*const u8>::h[HASH])
-  --> $DIR/types.rs:121:5
+  --> $DIR/types.rs:198:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<*const u8>)
-  --> $DIR/types.rs:121:5
+  --> $DIR/types.rs:198:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b26Type$LT$$BP$mut$u20$u8$GT$17h[HASH]E)
-  --> $DIR/types.rs:127:5
+  --> $DIR/types.rs:207:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<*mut u8>::h[HASH])
-  --> $DIR/types.rs:127:5
+  --> $DIR/types.rs:207:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<*mut u8>)
-  --> $DIR/types.rs:127:5
+  --> $DIR/types.rs:207:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b19Type$LT$$RF$str$GT$17h[HASH]E)
-  --> $DIR/types.rs:133:5
+  --> $DIR/types.rs:216:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<&str>::h[HASH])
-  --> $DIR/types.rs:133:5
+  --> $DIR/types.rs:216:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<&str>)
-  --> $DIR/types.rs:133:5
+  --> $DIR/types.rs:216:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b27Type$LT$$RF$mut$u20$str$GT$17h[HASH]E)
-  --> $DIR/types.rs:139:5
+  --> $DIR/types.rs:225:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<&mut str>::h[HASH])
-  --> $DIR/types.rs:139:5
+  --> $DIR/types.rs:225:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<&mut str>)
-  --> $DIR/types.rs:139:5
+  --> $DIR/types.rs:225:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$17h[HASH]E)
-  --> $DIR/types.rs:145:5
+  --> $DIR/types.rs:234:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[u8; 0]>::h[HASH])
-  --> $DIR/types.rs:145:5
+  --> $DIR/types.rs:234:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[u8; 0]>)
-  --> $DIR/types.rs:145:5
+  --> $DIR/types.rs:234:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b22Type$LT$fn$LP$$RP$$GT$17h[HASH]E)
-  --> $DIR/types.rs:151:5
+  --> $DIR/types.rs:243:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<fn()>::h[HASH])
-  --> $DIR/types.rs:151:5
+  --> $DIR/types.rs:243:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<fn()>)
-  --> $DIR/types.rs:151:5
+  --> $DIR/types.rs:243:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b60Type$LT$unsafe$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RP$$GT$17h[HASH]E)
-  --> $DIR/types.rs:157:5
+  --> $DIR/types.rs:252:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<unsafe extern "C" fn()>::h[HASH])
-  --> $DIR/types.rs:157:5
+  --> $DIR/types.rs:252:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<unsafe extern "C" fn()>)
-  --> $DIR/types.rs:157:5
+  --> $DIR/types.rs:252:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b34Type$LT$$u5b$T$u3b$$u20$N$u5d$$GT$17h[HASH]E)
-  --> $DIR/types.rs:163:5
+  --> $DIR/types.rs:261:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[T; N]>::h[HASH])
-  --> $DIR/types.rs:163:5
+  --> $DIR/types.rs:261:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[T; N]>)
-  --> $DIR/types.rs:163:5
+  --> $DIR/types.rs:261:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 78 previous errors
+error: aborting due to 84 previous errors
 
diff --git a/tests/ui/symbol-names/types.rs b/tests/ui/symbol-names/types.rs
index b121408..7ed19e0 100644
--- a/tests/ui/symbol-names/types.rs
+++ b/tests/ui/symbol-names/types.rs
@@ -1,169 +1,270 @@
 //@ build-fail
-//@ revisions: legacy verbose-legacy
-//@ compile-flags: --crate-name=a -C symbol-mangling-version=legacy -Z unstable-options
-//@[verbose-legacy]compile-flags: -Zverbose-internals
+//@ revisions: legacy verbose-legacy v0
+//@ compile-flags: --crate-name=a -Z unstable-options
+//@ [legacy] compile-flags: -Csymbol-mangling-version=legacy
+//@ [verbose-legacy] compile-flags: -Csymbol-mangling-version=legacy -Zverbose-internals
+//@ [v0] compile-flags: -Csymbol-mangling-version=v0
 //@ normalize-stderr-test: "h[[:xdigit:]]{16}" -> "h[HASH]"
+//@ [v0] normalize-stderr-test: "\[[[:xdigit:]]{16}\]" -> "[HASH]"
 
 #![feature(never_type)]
 #![feature(rustc_attrs)]
+#![feature(f128)]
+#![feature(f16)]
 
 pub fn b() {
     struct Type<T: ?Sized>(T);
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b16Type$LT$bool$GT$
-    //~| ERROR demangling(a::b::Type<bool>::
-    //~| ERROR demangling-alt(a::b::Type<bool>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b16Type$LT$bool$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<bool>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<bool>)
+    //[v0]~^^^^ ERROR symbol-name(_RMNvCsCRATE_HASH_1a1bINtB<REF>_4TypebE)
+    //[v0]~| ERROR ::b::Type<bool>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<bool>>)
     impl Type<bool> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b16Type$LT$char$GT$
-    //~| ERROR demangling(a::b::Type<char>::
-    //~| ERROR demangling-alt(a::b::Type<char>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b16Type$LT$char$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<char>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<char>)
+    //[v0]~^^^^ ERROR symbol-name(_RMs_NvCsCRATE_HASH_1a1bINtB<REF>_4TypecE)
+    //[v0]~| ERROR ::b::Type<char>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<char>>)
     impl Type<char> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b14Type$LT$i8$GT$
-    //~| ERROR demangling(a::b::Type<i8>::
-    //~| ERROR demangling-alt(a::b::Type<i8>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b14Type$LT$i8$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<i8>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<i8>)
+    //[v0]~^^^^ ERROR symbol-name(_RMs0_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeaE)
+    //[v0]~| ERROR ::b::Type<i8>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<i8>>)
     impl Type<i8> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b15Type$LT$i16$GT$
-    //~| ERROR demangling(a::b::Type<i16>::
-    //~| ERROR demangling-alt(a::b::Type<i16>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$i16$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<i16>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<i16>)
+    //[v0]~^^^^ ERROR symbol-name(_RMs1_NvCsCRATE_HASH_1a1bINtB<REF>_4TypesE)
+    //[v0]~| ERROR ::b::Type<i16>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<i16>>)
     impl Type<i16> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b15Type$LT$i32$GT$
-    //~| ERROR demangling(a::b::Type<i32>::
-    //~| ERROR demangling-alt(a::b::Type<i32>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$i32$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<i32>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<i32>)
+    //[v0]~^^^^ ERROR symbol-name(_RMs2_NvCsCRATE_HASH_1a1bINtB<REF>_4TypelE)
+    //[v0]~| ERROR ::b::Type<i32>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<i32>>)
     impl Type<i32> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b15Type$LT$i64$GT$
-    //~| ERROR demangling(a::b::Type<i64>::
-    //~| ERROR demangling-alt(a::b::Type<i64>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$i64$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<i64>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<i64>)
+    //[v0]~^^^^ ERROR symbol-name(_RMs3_NvCsCRATE_HASH_1a1bINtB<REF>_4TypexE)
+    //[v0]~| ERROR ::b::Type<i64>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<i64>>)
     impl Type<i64> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b14Type$LT$u8$GT$
-    //~| ERROR demangling(a::b::Type<u8>::
-    //~| ERROR demangling-alt(a::b::Type<u8>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b14Type$LT$u8$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<u8>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<u8>)
+    //[v0]~^^^^ ERROR symbol-name(_RMs4_NvCsCRATE_HASH_1a1bINtB<REF>_4TypehE)
+    //[v0]~| ERROR ::b::Type<u8>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<u8>>)
     impl Type<u8> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b15Type$LT$u16$GT$
-    //~| ERROR demangling(a::b::Type<u16>::
-    //~| ERROR demangling-alt(a::b::Type<u16>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$u16$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<u16>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<u16>)
+    //[v0]~^^^^ ERROR symbol-name(_RMs5_NvCsCRATE_HASH_1a1bINtB<REF>_4TypetE)
+    //[v0]~| ERROR ::b::Type<u16>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<u16>>)
     impl Type<u16> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b15Type$LT$u32$GT$
-    //~| ERROR demangling(a::b::Type<u32>::
-    //~| ERROR demangling-alt(a::b::Type<u32>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$u32$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<u32>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<u32>)
+    //[v0]~^^^^ ERROR symbol-name(_RMs6_NvCsCRATE_HASH_1a1bINtB<REF>_4TypemE)
+    //[v0]~| ERROR ::b::Type<u32>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<u32>>)
     impl Type<u32> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b15Type$LT$u64$GT$
-    //~| ERROR demangling(a::b::Type<u64>::
-    //~| ERROR demangling-alt(a::b::Type<u64>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$u64$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<u64>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<u64>)
+    //[v0]~^^^^ ERROR symbol-name(_RMs7_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeyE)
+    //[v0]~| ERROR ::b::Type<u64>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<u64>>)
     impl Type<u64> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b15Type$LT$f32$GT$
-    //~| ERROR demangling(a::b::Type<f32>::
-    //~| ERROR demangling-alt(a::b::Type<f32>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$f16$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<f16>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<f16>)
+    //[v0]~^^^^ ERROR symbol-name(_RMs8_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeC3f16E)
+    //[v0]~| ERROR ::b::Type<f16>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<f16>>)
+    impl Type<f16> {}
+
+    #[rustc_symbol_name]
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$f32$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<f32>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<f32>)
+    //[v0]~^^^^ ERROR symbol-name(_RMs9_NvCsCRATE_HASH_1a1bINtB<REF>_4TypefE)
+    //[v0]~| ERROR ::b::Type<f32>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<f32>>)
     impl Type<f32> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b15Type$LT$f64$GT$
-    //~| ERROR demangling(a::b::Type<f64>::
-    //~| ERROR demangling-alt(a::b::Type<f64>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$f64$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<f64>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<f64>)
+    //[v0]~^^^^ ERROR symbol-name(_RMsa_NvCsCRATE_HASH_1a1bINtB<REF>_4TypedE)
+    //[v0]~| ERROR ::b::Type<f64>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<f64>>)
     impl Type<f64> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b15Type$LT$str$GT$
-    //~| ERROR demangling(a::b::Type<str>::
-    //~| ERROR demangling-alt(a::b::Type<str>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b16Type$LT$f128$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<f128>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<f128>)
+    //[v0]~^^^^ ERROR symbol-name(_RMsb_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeC4f128E)
+    //[v0]~| ERROR ::b::Type<f128>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<f128>>)
+    impl Type<f128> {}
+
+    #[rustc_symbol_name]
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b15Type$LT$str$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<str>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<str>)
+    //[v0]~^^^^ ERROR symbol-name(_RMsc_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeeE)
+    //[v0]~| ERROR ::b::Type<str>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<str>>)
     impl Type<str> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b17Type$LT$$u21$$GT$
-    //~| ERROR demangling(a::b::Type<!>::
-    //~| ERROR demangling-alt(a::b::Type<!>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b17Type$LT$$u21$$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<!>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<!>)
+    //[v0]~^^^^ ERROR symbol-name(_RMsd_NvCsCRATE_HASH_1a1bINtB<REF>_4TypezE)
+    //[v0]~| ERROR ::b::Type<!>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<!>>)
     impl Type<!> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b20Type$LT$$LP$$RP$$GT
-    //~| ERROR demangling(a::b::Type<()>::
-    //~| ERROR demangling-alt(a::b::Type<()>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b20Type$LT$$LP$$RP$$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<()>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<()>)
+    //[v0]~^^^^ ERROR symbol-name(_RMse_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeuE)
+    //[v0]~| ERROR ::b::Type<()>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<()>>)
     impl Type<()> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b25Type$LT$$LP$u8$C$$RP$$GT$
-    //~| ERROR demangling(a::b::Type<(u8,)>::
-    //~| ERROR demangling-alt(a::b::Type<(u8,)>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b25Type$LT$$LP$u8$C$$RP$$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<(u8,)>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<(u8,)>)
+    //[v0]~^^^^ ERROR symbol-name(_RMsf_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeThEE)
+    //[v0]~| ERROR ::b::Type<(u8,)>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<(u8,)>>)
     impl Type<(u8,)> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b28Type$LT$$LP$u8$C$u16$RP$$GT$
-    //~| ERROR demangling(a::b::Type<(u8,u16)>::
-    //~| ERROR demangling-alt(a::b::Type<(u8,u16)>)
-    impl Type<(u8,u16)> {}
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b28Type$LT$$LP$u8$C$u16$RP$$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<(u8,u16)>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<(u8,u16)>)
+    //[v0]~^^^^ ERROR symbol-name(_RMsg_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeThtEE)
+    //[v0]~| ERROR ::b::Type<(u8, u16)>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<(u8, u16)>>)
+    impl Type<(u8, u16)> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b34Type$LT$$LP$u8$C$u16$C$u32$RP$$GT$
-    //~| ERROR demangling(a::b::Type<(u8,u16,u32)>::
-    //~| ERROR demangling-alt(a::b::Type<(u8,u16,u32)>)
-    impl Type<(u8,u16,u32)> {}
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b34Type$LT$$LP$u8$C$u16$C$u32$RP$$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<(u8,u16,u32)>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<(u8,u16,u32)>)
+    //[v0]~^^^^ ERROR symbol-name(_RMsh_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeThtmEE)
+    //[v0]~| ERROR ::b::Type<(u8, u16, u32)>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<(u8, u16, u32)>>)
+    impl Type<(u8, u16, u32)> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b28Type$LT$$BP$const$u20$u8$GT$
-    //~| ERROR demangling(a::b::Type<*const u8>::
-    //~| ERROR demangling-alt(a::b::Type<*const u8>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b28Type$LT$$BP$const$u20$u8$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<*const u8>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<*const u8>)
+    //[v0]~^^^^ ERROR symbol-name(_RMsi_NvCsCRATE_HASH_1a1bINtB<REF>_4TypePhE)
+    //[v0]~| ERROR ::b::Type<*const u8>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<*const u8>>)
     impl Type<*const u8> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b26Type$LT$$BP$mut$u20$u8$GT$
-    //~| ERROR demangling(a::b::Type<*mut u8>::
-    //~| ERROR demangling-alt(a::b::Type<*mut u8>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b26Type$LT$$BP$mut$u20$u8$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<*mut u8>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<*mut u8>)
+    //[v0]~^^^^ ERROR symbol-name(_RMsj_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeOhE)
+    //[v0]~| ERROR ::b::Type<*mut u8>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<*mut u8>>)
     impl Type<*mut u8> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b19Type$LT$$RF$str$GT$
-    //~| ERROR demangling(a::b::Type<&str>::
-    //~| ERROR demangling-alt(a::b::Type<&str>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b19Type$LT$$RF$str$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<&str>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<&str>)
+    //[v0]~^^^^ ERROR symbol-name(_RMsk_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeReE)
+    //[v0]~| ERROR ::b::Type<&str>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<&str>>)
     impl Type<&str> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b27Type$LT$$RF$mut$u20$str$GT$
-    //~| ERROR demangling(a::b::Type<&mut str>::
-    //~| ERROR demangling-alt(a::b::Type<&mut str>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b27Type$LT$$RF$mut$u20$str$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<&mut str>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<&mut str>)
+    //[v0]~^^^^ ERROR symbol-name(_RMsl_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeQeE)
+    //[v0]~| ERROR ::b::Type<&mut str>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<&mut str>>)
     impl Type<&mut str> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$
-    //~| ERROR demangling(a::b::Type<[u8; 0]>::
-    //~| ERROR demangling-alt(a::b::Type<[u8; 0]>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<[u8; 0]>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<[u8; 0]>)
+    //[v0]~^^^^ ERROR symbol-name(_RMsm_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeAhj0_E)
+    //[v0]~| ERROR ::b::Type<[u8; 0usize]>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<[u8; 0]>>)
     impl Type<[u8; 0]> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b22Type$LT$fn$LP$$RP$$GT$
-    //~| ERROR demangling(a::b::Type<fn()>::
-    //~| ERROR demangling-alt(a::b::Type<fn()>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b22Type$LT$fn$LP$$RP$$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<fn()>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<fn()>)
+    //[v0]~^^^^ ERROR symbol-name(_RMsn_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeFEuE)
+    //[v0]~| ERROR ::b::Type<fn()>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<fn()>>)
     impl Type<fn()> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b60Type$LT$unsafe$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RP$$GT$
-    //~| ERROR demangling(a::b::Type<unsafe extern "C" fn()>::
-    //~| ERROR demangling-alt(a::b::Type<unsafe extern "C" fn()>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b60Type$LT$unsafe$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RP$$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<unsafe extern "C" fn()>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<unsafe extern "C" fn()>)
+    //[v0]~^^^^ ERROR symbol-name(_RMso_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeFUKCEuE)
+    //[v0]~| ERROR ::b::Type<unsafe extern "C" fn()>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<unsafe extern "C" fn()>>)
     impl Type<unsafe extern "C" fn()> {}
 
     #[rustc_symbol_name]
-    //~^ ERROR symbol-name(_ZN1a1b34Type$LT$$u5b$T$u3b$$u20$N$u5d$$GT$
-    //~| ERROR demangling(a::b::Type<[T; N]>::
-    //~| ERROR demangling-alt(a::b::Type<[T; N]>)
+    //[legacy,verbose-legacy]~^ ERROR symbol-name(_ZN1a1b34Type$LT$$u5b$T$u3b$$u20$N$u5d$$GT$
+    //[legacy,verbose-legacy]~| ERROR demangling(a::b::Type<[T; N]>::
+    //[legacy,verbose-legacy]~| ERROR demangling-alt(a::b::Type<[T; N]>)
+    //[v0]~^^^^ ERROR symbol-name(_RMsp_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeAppEB<REF>_)
+    //[v0]~| ERROR ::b::Type<[_; _]>>)
+    //[v0]~| ERROR demangling-alt(<a::b::Type<[_; _]>>)
     impl<const N: usize, T> Type<[T; N]> {}
 }
 
diff --git a/tests/ui/symbol-names/types.v0.stderr b/tests/ui/symbol-names/types.v0.stderr
new file mode 100644
index 0000000..58680e0
--- /dev/null
+++ b/tests/ui/symbol-names/types.v0.stderr
@@ -0,0 +1,506 @@
+error: symbol-name(_RMNvCsCRATE_HASH_1a1bINtB<REF>_4TypebE)
+  --> $DIR/types.rs:18:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<bool>>)
+  --> $DIR/types.rs:18:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<bool>>)
+  --> $DIR/types.rs:18:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMs_NvCsCRATE_HASH_1a1bINtB<REF>_4TypecE)
+  --> $DIR/types.rs:27:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<char>>)
+  --> $DIR/types.rs:27:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<char>>)
+  --> $DIR/types.rs:27:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMs0_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeaE)
+  --> $DIR/types.rs:36:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<i8>>)
+  --> $DIR/types.rs:36:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<i8>>)
+  --> $DIR/types.rs:36:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMs1_NvCsCRATE_HASH_1a1bINtB<REF>_4TypesE)
+  --> $DIR/types.rs:45:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<i16>>)
+  --> $DIR/types.rs:45:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<i16>>)
+  --> $DIR/types.rs:45:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMs2_NvCsCRATE_HASH_1a1bINtB<REF>_4TypelE)
+  --> $DIR/types.rs:54:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<i32>>)
+  --> $DIR/types.rs:54:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<i32>>)
+  --> $DIR/types.rs:54:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMs3_NvCsCRATE_HASH_1a1bINtB<REF>_4TypexE)
+  --> $DIR/types.rs:63:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<i64>>)
+  --> $DIR/types.rs:63:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<i64>>)
+  --> $DIR/types.rs:63:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMs4_NvCsCRATE_HASH_1a1bINtB<REF>_4TypehE)
+  --> $DIR/types.rs:72:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<u8>>)
+  --> $DIR/types.rs:72:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<u8>>)
+  --> $DIR/types.rs:72:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMs5_NvCsCRATE_HASH_1a1bINtB<REF>_4TypetE)
+  --> $DIR/types.rs:81:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<u16>>)
+  --> $DIR/types.rs:81:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<u16>>)
+  --> $DIR/types.rs:81:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMs6_NvCsCRATE_HASH_1a1bINtB<REF>_4TypemE)
+  --> $DIR/types.rs:90:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<u32>>)
+  --> $DIR/types.rs:90:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<u32>>)
+  --> $DIR/types.rs:90:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMs7_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeyE)
+  --> $DIR/types.rs:99:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<u64>>)
+  --> $DIR/types.rs:99:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<u64>>)
+  --> $DIR/types.rs:99:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMs8_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeC3f16E)
+  --> $DIR/types.rs:108:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<f16>>)
+  --> $DIR/types.rs:108:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<f16>>)
+  --> $DIR/types.rs:108:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMs9_NvCsCRATE_HASH_1a1bINtB<REF>_4TypefE)
+  --> $DIR/types.rs:117:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<f32>>)
+  --> $DIR/types.rs:117:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<f32>>)
+  --> $DIR/types.rs:117:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMsa_NvCsCRATE_HASH_1a1bINtB<REF>_4TypedE)
+  --> $DIR/types.rs:126:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<f64>>)
+  --> $DIR/types.rs:126:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<f64>>)
+  --> $DIR/types.rs:126:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMsb_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeC4f128E)
+  --> $DIR/types.rs:135:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<f128>>)
+  --> $DIR/types.rs:135:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<f128>>)
+  --> $DIR/types.rs:135:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMsc_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeeE)
+  --> $DIR/types.rs:144:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<str>>)
+  --> $DIR/types.rs:144:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<str>>)
+  --> $DIR/types.rs:144:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMsd_NvCsCRATE_HASH_1a1bINtB<REF>_4TypezE)
+  --> $DIR/types.rs:153:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<!>>)
+  --> $DIR/types.rs:153:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<!>>)
+  --> $DIR/types.rs:153:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMse_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeuE)
+  --> $DIR/types.rs:162:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<()>>)
+  --> $DIR/types.rs:162:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<()>>)
+  --> $DIR/types.rs:162:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMsf_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeThEE)
+  --> $DIR/types.rs:171:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<(u8,)>>)
+  --> $DIR/types.rs:171:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<(u8,)>>)
+  --> $DIR/types.rs:171:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMsg_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeThtEE)
+  --> $DIR/types.rs:180:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<(u8, u16)>>)
+  --> $DIR/types.rs:180:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<(u8, u16)>>)
+  --> $DIR/types.rs:180:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMsh_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeThtmEE)
+  --> $DIR/types.rs:189:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<(u8, u16, u32)>>)
+  --> $DIR/types.rs:189:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<(u8, u16, u32)>>)
+  --> $DIR/types.rs:189:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMsi_NvCsCRATE_HASH_1a1bINtB<REF>_4TypePhE)
+  --> $DIR/types.rs:198:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<*const u8>>)
+  --> $DIR/types.rs:198:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<*const u8>>)
+  --> $DIR/types.rs:198:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMsj_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeOhE)
+  --> $DIR/types.rs:207:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<*mut u8>>)
+  --> $DIR/types.rs:207:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<*mut u8>>)
+  --> $DIR/types.rs:207:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMsk_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeReE)
+  --> $DIR/types.rs:216:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<&str>>)
+  --> $DIR/types.rs:216:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<&str>>)
+  --> $DIR/types.rs:216:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMsl_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeQeE)
+  --> $DIR/types.rs:225:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<&mut str>>)
+  --> $DIR/types.rs:225:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<&mut str>>)
+  --> $DIR/types.rs:225:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMsm_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeAhj0_E)
+  --> $DIR/types.rs:234:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<[u8; 0usize]>>)
+  --> $DIR/types.rs:234:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<[u8; 0]>>)
+  --> $DIR/types.rs:234:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMsn_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeFEuE)
+  --> $DIR/types.rs:243:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<fn()>>)
+  --> $DIR/types.rs:243:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<fn()>>)
+  --> $DIR/types.rs:243:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMso_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeFUKCEuE)
+  --> $DIR/types.rs:252:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<unsafe extern "C" fn()>>)
+  --> $DIR/types.rs:252:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<unsafe extern "C" fn()>>)
+  --> $DIR/types.rs:252:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_RMsp_NvCsCRATE_HASH_1a1bINtB<REF>_4TypeAppEB<REF>_)
+  --> $DIR/types.rs:261:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(<a[HASH]::b::Type<[_; _]>>)
+  --> $DIR/types.rs:261:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(<a::b::Type<[_; _]>>)
+  --> $DIR/types.rs:261:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: aborting due to 84 previous errors
+
diff --git a/tests/ui/symbol-names/types.verbose-legacy.stderr b/tests/ui/symbol-names/types.verbose-legacy.stderr
index a4984d5..87c3aca 100644
--- a/tests/ui/symbol-names/types.verbose-legacy.stderr
+++ b/tests/ui/symbol-names/types.verbose-legacy.stderr
@@ -1,470 +1,506 @@
 error: symbol-name(_ZN1a1b16Type$LT$bool$GT$17h[HASH]E)
-  --> $DIR/types.rs:13:5
+  --> $DIR/types.rs:18:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<bool>::h[HASH])
-  --> $DIR/types.rs:13:5
+  --> $DIR/types.rs:18:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<bool>)
-  --> $DIR/types.rs:13:5
+  --> $DIR/types.rs:18:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b16Type$LT$char$GT$17h[HASH]E)
-  --> $DIR/types.rs:19:5
+  --> $DIR/types.rs:27:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<char>::h[HASH])
-  --> $DIR/types.rs:19:5
+  --> $DIR/types.rs:27:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<char>)
-  --> $DIR/types.rs:19:5
+  --> $DIR/types.rs:27:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b14Type$LT$i8$GT$17h[HASH]E)
-  --> $DIR/types.rs:25:5
+  --> $DIR/types.rs:36:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i8>::h[HASH])
-  --> $DIR/types.rs:25:5
+  --> $DIR/types.rs:36:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i8>)
-  --> $DIR/types.rs:25:5
+  --> $DIR/types.rs:36:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i16$GT$17h[HASH]E)
-  --> $DIR/types.rs:31:5
+  --> $DIR/types.rs:45:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i16>::h[HASH])
-  --> $DIR/types.rs:31:5
+  --> $DIR/types.rs:45:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i16>)
-  --> $DIR/types.rs:31:5
+  --> $DIR/types.rs:45:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i32$GT$17h[HASH]E)
-  --> $DIR/types.rs:37:5
+  --> $DIR/types.rs:54:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i32>::h[HASH])
-  --> $DIR/types.rs:37:5
+  --> $DIR/types.rs:54:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i32>)
-  --> $DIR/types.rs:37:5
+  --> $DIR/types.rs:54:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$i64$GT$17h[HASH]E)
-  --> $DIR/types.rs:43:5
+  --> $DIR/types.rs:63:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<i64>::h[HASH])
-  --> $DIR/types.rs:43:5
+  --> $DIR/types.rs:63:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<i64>)
-  --> $DIR/types.rs:43:5
+  --> $DIR/types.rs:63:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b14Type$LT$u8$GT$17h[HASH]E)
-  --> $DIR/types.rs:49:5
+  --> $DIR/types.rs:72:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u8>::h[HASH])
-  --> $DIR/types.rs:49:5
+  --> $DIR/types.rs:72:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u8>)
-  --> $DIR/types.rs:49:5
+  --> $DIR/types.rs:72:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u16$GT$17h[HASH]E)
-  --> $DIR/types.rs:55:5
+  --> $DIR/types.rs:81:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u16>::h[HASH])
-  --> $DIR/types.rs:55:5
+  --> $DIR/types.rs:81:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u16>)
-  --> $DIR/types.rs:55:5
+  --> $DIR/types.rs:81:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u32$GT$17h[HASH]E)
-  --> $DIR/types.rs:61:5
+  --> $DIR/types.rs:90:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u32>::h[HASH])
-  --> $DIR/types.rs:61:5
+  --> $DIR/types.rs:90:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u32>)
-  --> $DIR/types.rs:61:5
+  --> $DIR/types.rs:90:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$u64$GT$17h[HASH]E)
-  --> $DIR/types.rs:67:5
+  --> $DIR/types.rs:99:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<u64>::h[HASH])
-  --> $DIR/types.rs:67:5
+  --> $DIR/types.rs:99:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<u64>)
-  --> $DIR/types.rs:67:5
+  --> $DIR/types.rs:99:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_ZN1a1b15Type$LT$f16$GT$17h[HASH]E)
+  --> $DIR/types.rs:108:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(a::b::Type<f16>::h[HASH])
+  --> $DIR/types.rs:108:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(a::b::Type<f16>)
+  --> $DIR/types.rs:108:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f32$GT$17h[HASH]E)
-  --> $DIR/types.rs:73:5
+  --> $DIR/types.rs:117:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f32>::h[HASH])
-  --> $DIR/types.rs:73:5
+  --> $DIR/types.rs:117:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f32>)
-  --> $DIR/types.rs:73:5
+  --> $DIR/types.rs:117:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$f64$GT$17h[HASH]E)
-  --> $DIR/types.rs:79:5
+  --> $DIR/types.rs:126:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<f64>::h[HASH])
-  --> $DIR/types.rs:79:5
+  --> $DIR/types.rs:126:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<f64>)
-  --> $DIR/types.rs:79:5
+  --> $DIR/types.rs:126:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: symbol-name(_ZN1a1b16Type$LT$f128$GT$17h[HASH]E)
+  --> $DIR/types.rs:135:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling(a::b::Type<f128>::h[HASH])
+  --> $DIR/types.rs:135:5
+   |
+LL |     #[rustc_symbol_name]
+   |     ^^^^^^^^^^^^^^^^^^^^
+
+error: demangling-alt(a::b::Type<f128>)
+  --> $DIR/types.rs:135:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b15Type$LT$str$GT$17h[HASH]E)
-  --> $DIR/types.rs:85:5
+  --> $DIR/types.rs:144:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<str>::h[HASH])
-  --> $DIR/types.rs:85:5
+  --> $DIR/types.rs:144:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<str>)
-  --> $DIR/types.rs:85:5
+  --> $DIR/types.rs:144:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b17Type$LT$$u21$$GT$17h[HASH]E)
-  --> $DIR/types.rs:91:5
+  --> $DIR/types.rs:153:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<!>::h[HASH])
-  --> $DIR/types.rs:91:5
+  --> $DIR/types.rs:153:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<!>)
-  --> $DIR/types.rs:91:5
+  --> $DIR/types.rs:153:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b20Type$LT$$LP$$RP$$GT$17h[HASH]E)
-  --> $DIR/types.rs:97:5
+  --> $DIR/types.rs:162:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<()>::h[HASH])
-  --> $DIR/types.rs:97:5
+  --> $DIR/types.rs:162:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<()>)
-  --> $DIR/types.rs:97:5
+  --> $DIR/types.rs:162:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b25Type$LT$$LP$u8$C$$RP$$GT$17h[HASH]E)
-  --> $DIR/types.rs:103:5
+  --> $DIR/types.rs:171:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,)>::h[HASH])
-  --> $DIR/types.rs:103:5
+  --> $DIR/types.rs:171:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,)>)
-  --> $DIR/types.rs:103:5
+  --> $DIR/types.rs:171:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b28Type$LT$$LP$u8$C$u16$RP$$GT$17h[HASH]E)
-  --> $DIR/types.rs:109:5
+  --> $DIR/types.rs:180:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,u16)>::h[HASH])
-  --> $DIR/types.rs:109:5
+  --> $DIR/types.rs:180:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,u16)>)
-  --> $DIR/types.rs:109:5
+  --> $DIR/types.rs:180:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b34Type$LT$$LP$u8$C$u16$C$u32$RP$$GT$17h[HASH]E)
-  --> $DIR/types.rs:115:5
+  --> $DIR/types.rs:189:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<(u8,u16,u32)>::h[HASH])
-  --> $DIR/types.rs:115:5
+  --> $DIR/types.rs:189:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<(u8,u16,u32)>)
-  --> $DIR/types.rs:115:5
+  --> $DIR/types.rs:189:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b28Type$LT$$BP$const$u20$u8$GT$17h[HASH]E)
-  --> $DIR/types.rs:121:5
+  --> $DIR/types.rs:198:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<*const u8>::h[HASH])
-  --> $DIR/types.rs:121:5
+  --> $DIR/types.rs:198:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<*const u8>)
-  --> $DIR/types.rs:121:5
+  --> $DIR/types.rs:198:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b26Type$LT$$BP$mut$u20$u8$GT$17h[HASH]E)
-  --> $DIR/types.rs:127:5
+  --> $DIR/types.rs:207:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<*mut u8>::h[HASH])
-  --> $DIR/types.rs:127:5
+  --> $DIR/types.rs:207:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<*mut u8>)
-  --> $DIR/types.rs:127:5
+  --> $DIR/types.rs:207:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b19Type$LT$$RF$str$GT$17h[HASH]E)
-  --> $DIR/types.rs:133:5
+  --> $DIR/types.rs:216:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<&str>::h[HASH])
-  --> $DIR/types.rs:133:5
+  --> $DIR/types.rs:216:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<&str>)
-  --> $DIR/types.rs:133:5
+  --> $DIR/types.rs:216:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b27Type$LT$$RF$mut$u20$str$GT$17h[HASH]E)
-  --> $DIR/types.rs:139:5
+  --> $DIR/types.rs:225:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<&mut str>::h[HASH])
-  --> $DIR/types.rs:139:5
+  --> $DIR/types.rs:225:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<&mut str>)
-  --> $DIR/types.rs:139:5
+  --> $DIR/types.rs:225:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b35Type$LT$$u5b$u8$u3b$$u20$0$u5d$$GT$17h[HASH]E)
-  --> $DIR/types.rs:145:5
+  --> $DIR/types.rs:234:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[u8; 0]>::h[HASH])
-  --> $DIR/types.rs:145:5
+  --> $DIR/types.rs:234:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[u8; 0]>)
-  --> $DIR/types.rs:145:5
+  --> $DIR/types.rs:234:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b22Type$LT$fn$LP$$RP$$GT$17h[HASH]E)
-  --> $DIR/types.rs:151:5
+  --> $DIR/types.rs:243:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<fn()>::h[HASH])
-  --> $DIR/types.rs:151:5
+  --> $DIR/types.rs:243:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<fn()>)
-  --> $DIR/types.rs:151:5
+  --> $DIR/types.rs:243:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b60Type$LT$unsafe$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RP$$GT$17h[HASH]E)
-  --> $DIR/types.rs:157:5
+  --> $DIR/types.rs:252:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<unsafe extern "C" fn()>::h[HASH])
-  --> $DIR/types.rs:157:5
+  --> $DIR/types.rs:252:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<unsafe extern "C" fn()>)
-  --> $DIR/types.rs:157:5
+  --> $DIR/types.rs:252:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: symbol-name(_ZN1a1b34Type$LT$$u5b$T$u3b$$u20$N$u5d$$GT$17h[HASH]E)
-  --> $DIR/types.rs:163:5
+  --> $DIR/types.rs:261:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling(a::b::Type<[T; N]>::h[HASH])
-  --> $DIR/types.rs:163:5
+  --> $DIR/types.rs:261:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
 error: demangling-alt(a::b::Type<[T; N]>)
-  --> $DIR/types.rs:163:5
+  --> $DIR/types.rs:261:5
    |
 LL |     #[rustc_symbol_name]
    |     ^^^^^^^^^^^^^^^^^^^^
 
-error: aborting due to 78 previous errors
+error: aborting due to 84 previous errors
 
diff --git a/tests/ui/target-feature/tied-features-cli.rs b/tests/ui/target-feature/tied-features-cli.rs
index 1168245..17c1382 100644
--- a/tests/ui/target-feature/tied-features-cli.rs
+++ b/tests/ui/target-feature/tied-features-cli.rs
@@ -1,4 +1,4 @@
-//@ revisions: one two three
+//@ revisions: one two three four
 //@ compile-flags: --crate-type=rlib --target=aarch64-unknown-linux-gnu
 //@ needs-llvm-components: aarch64
 //
diff --git a/tests/ui/tool_lints-fail.rs b/tests/ui/tool-attributes/tool_lints-fail.rs
similarity index 100%
rename from tests/ui/tool_lints-fail.rs
rename to tests/ui/tool-attributes/tool_lints-fail.rs
diff --git a/tests/ui/tool_lints-fail.stderr b/tests/ui/tool-attributes/tool_lints-fail.stderr
similarity index 100%
rename from tests/ui/tool_lints-fail.stderr
rename to tests/ui/tool-attributes/tool_lints-fail.stderr
diff --git a/tests/ui/tool_lints-rpass.rs b/tests/ui/tool-attributes/tool_lints-rpass.rs
similarity index 100%
rename from tests/ui/tool_lints-rpass.rs
rename to tests/ui/tool-attributes/tool_lints-rpass.rs
diff --git a/tests/ui/tool_lints.rs b/tests/ui/tool-attributes/tool_lints.rs
similarity index 100%
rename from tests/ui/tool_lints.rs
rename to tests/ui/tool-attributes/tool_lints.rs
diff --git a/tests/ui/tool_lints.stderr b/tests/ui/tool-attributes/tool_lints.stderr
similarity index 100%
rename from tests/ui/tool_lints.stderr
rename to tests/ui/tool-attributes/tool_lints.stderr
diff --git a/tests/ui/tool_lints_2018_preview.rs b/tests/ui/tool-attributes/tool_lints_2018_preview.rs
similarity index 100%
rename from tests/ui/tool_lints_2018_preview.rs
rename to tests/ui/tool-attributes/tool_lints_2018_preview.rs
diff --git a/tests/ui/unknown-lint-tool-name.rs b/tests/ui/tool-attributes/unknown-lint-tool-name.rs
similarity index 100%
rename from tests/ui/unknown-lint-tool-name.rs
rename to tests/ui/tool-attributes/unknown-lint-tool-name.rs
diff --git a/tests/ui/unknown-lint-tool-name.stderr b/tests/ui/tool-attributes/unknown-lint-tool-name.stderr
similarity index 100%
rename from tests/ui/unknown-lint-tool-name.stderr
rename to tests/ui/tool-attributes/unknown-lint-tool-name.stderr
diff --git a/tests/ui/unknown-tool-name.rs b/tests/ui/tool-attributes/unknown-tool-name.rs
similarity index 100%
rename from tests/ui/unknown-tool-name.rs
rename to tests/ui/tool-attributes/unknown-tool-name.rs
diff --git a/tests/ui/unknown-tool-name.stderr b/tests/ui/tool-attributes/unknown-tool-name.stderr
similarity index 100%
rename from tests/ui/unknown-tool-name.stderr
rename to tests/ui/tool-attributes/unknown-tool-name.stderr
diff --git a/tests/ui/traits/impl-method-mismatch.stderr b/tests/ui/traits/impl-method-mismatch.stderr
index 2061fc7..77d542c 100644
--- a/tests/ui/traits/impl-method-mismatch.stderr
+++ b/tests/ui/traits/impl-method-mismatch.stderr
@@ -2,7 +2,7 @@
   --> $DIR/impl-method-mismatch.rs:7:5
    |
 LL |     unsafe fn jumbo(&self, x: &usize) { *self + *x; }
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected normal fn, found unsafe fn
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected safe fn, found unsafe fn
    |
 note: type in trait
   --> $DIR/impl-method-mismatch.rs:2:5
diff --git a/tests/ui/traits/method-on-unbounded-type-param.stderr b/tests/ui/traits/method-on-unbounded-type-param.stderr
index 4d968e7..0b1f83a 100644
--- a/tests/ui/traits/method-on-unbounded-type-param.stderr
+++ b/tests/ui/traits/method-on-unbounded-type-param.stderr
@@ -76,8 +76,8 @@
            which is required by `&mut dyn T: Iterator`
    = help: items from traits can only be used if the trait is implemented and in scope
    = note: the following traits define an item `cmp`, perhaps you need to implement one of them:
-           candidate #1: `Iterator`
-           candidate #2: `Ord`
+           candidate #1: `Ord`
+   = note: the trait `Iterator` defines an item `cmp`, but is explicitly unimplemented
 
 error: aborting due to 4 previous errors
 
diff --git a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
index 044c24f..170f2c7 100644
--- a/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
+++ b/tests/ui/traits/next-solver/canonical/const-region-infer-to-static-in-binder.stderr
@@ -1,8 +1,8 @@
-error[E0282]: type annotations needed
+error[E0284]: type annotations needed: cannot satisfy `the constant `{ || {} }` can be evaluated`
   --> $DIR/const-region-infer-to-static-in-binder.rs:4:10
    |
 LL | struct X<const FN: fn() = { || {} }>;
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `{ || {} }`
+   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `the constant `{ || {} }` can be evaluated`
 
 error: using function pointers as const generic parameters is forbidden
   --> $DIR/const-region-infer-to-static-in-binder.rs:4:20
@@ -23,4 +23,4 @@
 
 error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0284`.
diff --git a/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-1.rs b/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-1.rs
new file mode 100644
index 0000000..151c3b2
--- /dev/null
+++ b/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-1.rs
@@ -0,0 +1,43 @@
+//@ compile-flags: -Znext-solver=coherence
+//@ check-pass
+
+// A regression test for #124791. Computing ambiguity causes
+// for the overlap of the `ToString` impls caused an ICE.
+#![crate_type = "lib"]
+#![feature(min_specialization)]
+trait Display {}
+
+trait ToOwned {
+    type Owned;
+}
+
+impl<T> ToOwned for T {
+    type Owned = T;
+}
+
+struct Cow<B: ?Sized>(B);
+
+impl<B: ?Sized> Display for Cow<B>
+where
+    B: ToOwned,
+    B::Owned: Display,
+{
+}
+
+impl Display for () {}
+
+trait ToString {
+    fn to_string();
+}
+
+impl<T: Display + ?Sized> ToString for T {
+    default fn to_string() {}
+}
+
+impl ToString for Cow<str> {
+    fn to_string() {}
+}
+
+impl ToOwned for str {
+    type Owned = ();
+}
diff --git a/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-2.rs b/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-2.rs
new file mode 100644
index 0000000..b472499
--- /dev/null
+++ b/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-2.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: -Znext-solver=coherence
+
+// A regression test for #124791. Computing ambiguity causes
+// for the overlap of the `ToString` impls caused an ICE.
+#![crate_type = "lib"]
+trait ToOwned {
+    type Owned;
+}
+impl<T> ToOwned for T {
+    type Owned = u8;
+}
+impl ToOwned for str {
+    type Owned = i8;
+}
+
+trait Overlap {}
+impl<T: ToOwned<Owned = i8> + ?Sized> Overlap for T {}
+impl Overlap for str {}
+//~^ ERROR conflicting implementations of trait `Overlap`
diff --git a/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-2.stderr b/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-2.stderr
new file mode 100644
index 0000000..469f7a9
--- /dev/null
+++ b/tests/ui/traits/next-solver/coherence/ambiguity-causes-canonical-state-ice-2.stderr
@@ -0,0 +1,11 @@
+error[E0119]: conflicting implementations of trait `Overlap` for type `str`
+  --> $DIR/ambiguity-causes-canonical-state-ice-2.rs:18:1
+   |
+LL | impl<T: ToOwned<Owned = i8> + ?Sized> Overlap for T {}
+   | --------------------------------------------------- first implementation here
+LL | impl Overlap for str {}
+   | ^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `str`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
index 6e68646..57cba79 100644
--- a/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
+++ b/tests/ui/traits/next-solver/coherence/coherence-fulfill-overflow.stderr
@@ -1,12 +1,12 @@
-error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>`
+error[E0119]: conflicting implementations of trait `Trait` for type `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>`
   --> $DIR/coherence-fulfill-overflow.rs:12:1
    |
 LL | impl<T: ?Sized + TwoW> Trait for W<T> {}
    | ------------------------------------- first implementation here
 LL | impl<T: ?Sized + TwoW> Trait for T {}
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>>`
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>`
    |
-   = note: overflow evaluating the requirement `W<W<W<W<_>>>>: TwoW`
+   = note: overflow evaluating the requirement `W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>>>>>>>>>>>: TwoW`
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "20"]` attribute to your crate (`coherence_fulfill_overflow`)
 
 error: aborting due to 1 previous error
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr
index df25150..8d7d8ce 100644
--- a/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr
+++ b/tests/ui/traits/next-solver/cycles/coinduction/fixpoint-exponential-growth.stderr
@@ -1,16 +1,9 @@
-error[E0275]: overflow evaluating the requirement `_: Sized`
+error[E0275]: overflow evaluating the requirement `W<_>: Trait`
   --> $DIR/fixpoint-exponential-growth.rs:33:13
    |
 LL |     impls::<W<_>>();
    |             ^^^^
    |
-note: required for `W<(W<_>, W<_>)>` to implement `Trait`
-  --> $DIR/fixpoint-exponential-growth.rs:23:12
-   |
-LL | impl<T, U> Trait for W<(W<T>, W<U>)>
-   |      -     ^^^^^     ^^^^^^^^^^^^^^^
-   |      |
-   |      unsatisfied trait bound introduced here
 note: required by a bound in `impls`
   --> $DIR/fixpoint-exponential-growth.rs:30:13
    |
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs
index 8bb4ff4..920f8ad 100644
--- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs
+++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.rs
@@ -1,3 +1,4 @@
+//@ revisions: with without
 //@ compile-flags: -Znext-solver
 #![feature(rustc_attrs)]
 
@@ -56,12 +57,13 @@
     X: IncompleteGuidance<u32, i8>,
     X: IncompleteGuidance<u32, i16>,
 {
+    #[cfg(with)]
     impls_trait::<B<X>, _, _, _>(); // entering the cycle from `B` works
 
     // entering the cycle from `A` fails, but would work if we were to use the cache
     // result of `B<X>`.
     impls_trait::<A<X>, _, _, _>();
-    //~^ ERROR the trait bound `A<X>: Trait<i32, u8, u8>` is not satisfied
+    //~^ ERROR the trait bound `A<X>: Trait<_, _, _>` is not satisfied
 }
 
 fn main() {
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.stderr
deleted file mode 100644
index cdb4ff4..0000000
--- a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.stderr
+++ /dev/null
@@ -1,29 +0,0 @@
-error[E0277]: the trait bound `A<X>: Trait<i32, u8, u8>` is not satisfied
-  --> $DIR/incompleteness-unstable-result.rs:63:19
-   |
-LL |     impls_trait::<A<X>, _, _, _>();
-   |                   ^^^^ the trait `Trait<i32, u8, u8>` is not implemented for `A<X>`, which is required by `A<X>: Trait<_, _, _>`
-   |
-note: required for `A<X>` to implement `Trait<i32, u8, u8>`
-  --> $DIR/incompleteness-unstable-result.rs:32:50
-   |
-LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
-   |                                                  ^^^^^^^^^^^^^^     ^^^^
-...
-LL |     A<T>: Trait<U, D, V>,
-   |           -------------- unsatisfied trait bound introduced here
-   = note: 8 redundant requirements hidden
-   = note: required for `A<X>` to implement `Trait<i32, u8, u8>`
-note: required by a bound in `impls_trait`
-  --> $DIR/incompleteness-unstable-result.rs:51:28
-   |
-LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
-   |                            ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
-help: consider extending the `where` clause, but there might be an alternative better way to express this requirement
-   |
-LL |     X: IncompleteGuidance<u32, i16>, A<X>: Trait<i32, u8, u8>
-   |                                    ~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-error: aborting due to 1 previous error
-
-For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr
new file mode 100644
index 0000000..a81229e
--- /dev/null
+++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.with.stderr
@@ -0,0 +1,26 @@
+error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied
+  --> $DIR/incompleteness-unstable-result.rs:65:19
+   |
+LL |     impls_trait::<A<X>, _, _, _>();
+   |                   ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`, which is required by `A<X>: Trait<_, _, _>`
+   |
+   = help: the trait `Trait<U, V, D>` is implemented for `A<T>`
+note: required for `A<X>` to implement `Trait<_, _, _>`
+  --> $DIR/incompleteness-unstable-result.rs:33:50
+   |
+LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
+   |                                                  ^^^^^^^^^^^^^^     ^^^^
+...
+LL |     A<T>: Trait<U, D, V>,
+   |           -------------- unsatisfied trait bound introduced here
+   = note: 8 redundant requirements hidden
+   = note: required for `A<X>` to implement `Trait<_, _, _>`
+note: required by a bound in `impls_trait`
+  --> $DIR/incompleteness-unstable-result.rs:52:28
+   |
+LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
+   |                            ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr
new file mode 100644
index 0000000..a81229e
--- /dev/null
+++ b/tests/ui/traits/next-solver/cycles/coinduction/incompleteness-unstable-result.without.stderr
@@ -0,0 +1,26 @@
+error[E0277]: the trait bound `A<X>: Trait<_, _, _>` is not satisfied
+  --> $DIR/incompleteness-unstable-result.rs:65:19
+   |
+LL |     impls_trait::<A<X>, _, _, _>();
+   |                   ^^^^ the trait `Trait<_, _, _>` is not implemented for `A<X>`, which is required by `A<X>: Trait<_, _, _>`
+   |
+   = help: the trait `Trait<U, V, D>` is implemented for `A<T>`
+note: required for `A<X>` to implement `Trait<_, _, _>`
+  --> $DIR/incompleteness-unstable-result.rs:33:50
+   |
+LL | impl<T: ?Sized, U: ?Sized, V: ?Sized, D: ?Sized> Trait<U, V, D> for A<T>
+   |                                                  ^^^^^^^^^^^^^^     ^^^^
+...
+LL |     A<T>: Trait<U, D, V>,
+   |           -------------- unsatisfied trait bound introduced here
+   = note: 8 redundant requirements hidden
+   = note: required for `A<X>` to implement `Trait<_, _, _>`
+note: required by a bound in `impls_trait`
+  --> $DIR/incompleteness-unstable-result.rs:52:28
+   |
+LL | fn impls_trait<T: ?Sized + Trait<U, V, D>, U: ?Sized, V: ?Sized, D: ?Sized>() {}
+   |                            ^^^^^^^^^^^^^^ required by this bound in `impls_trait`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr
index 86c71ad..7cedb4d 100644
--- a/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr
+++ b/tests/ui/traits/next-solver/cycles/double-cycle-inductive-coinductive.stderr
@@ -1,53 +1,21 @@
-error[E0275]: overflow evaluating the requirement `(): Inductive`
+error[E0275]: overflow evaluating the requirement `(): Trait`
   --> $DIR/double-cycle-inductive-coinductive.rs:32:19
    |
 LL |     impls_trait::<()>();
    |                   ^^
    |
-note: required for `()` to implement `Trait`
-  --> $DIR/double-cycle-inductive-coinductive.rs:9:34
-   |
-LL | impl<T: Inductive + Coinductive> Trait for T {}
-   |         ---------                ^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `Inductive`
-  --> $DIR/double-cycle-inductive-coinductive.rs:12:16
-   |
-LL | impl<T: Trait> Inductive for T {}
-   |         -----  ^^^^^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 7 redundant requirements hidden
-   = note: required for `()` to implement `Trait`
 note: required by a bound in `impls_trait`
   --> $DIR/double-cycle-inductive-coinductive.rs:17:19
    |
 LL | fn impls_trait<T: Trait>() {}
    |                   ^^^^^ required by this bound in `impls_trait`
 
-error[E0275]: overflow evaluating the requirement `(): CoinductiveRev`
+error[E0275]: overflow evaluating the requirement `(): TraitRev`
   --> $DIR/double-cycle-inductive-coinductive.rs:35:23
    |
 LL |     impls_trait_rev::<()>();
    |                       ^^
    |
-note: required for `()` to implement `TraitRev`
-  --> $DIR/double-cycle-inductive-coinductive.rs:21:40
-   |
-LL | impl<T: CoinductiveRev + InductiveRev> TraitRev for T {}
-   |         --------------                 ^^^^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `CoinductiveRev`
-  --> $DIR/double-cycle-inductive-coinductive.rs:27:19
-   |
-LL | impl<T: TraitRev> CoinductiveRev for T {}
-   |         --------  ^^^^^^^^^^^^^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 7 redundant requirements hidden
-   = note: required for `()` to implement `TraitRev`
 note: required by a bound in `impls_trait_rev`
   --> $DIR/double-cycle-inductive-coinductive.rs:29:23
    |
diff --git a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
index ea46c0f..a2a5c02 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
+++ b/tests/ui/traits/next-solver/cycles/inductive-fixpoint-hang.stderr
@@ -1,19 +1,9 @@
-error[E0275]: overflow evaluating the requirement `W<W<_>>: Trait`
+error[E0275]: overflow evaluating the requirement `W<_>: Trait`
   --> $DIR/inductive-fixpoint-hang.rs:31:19
    |
 LL |     impls_trait::<W<_>>();
    |                   ^^^^
    |
-note: required for `W<W<W<_>>>` to implement `Trait`
-  --> $DIR/inductive-fixpoint-hang.rs:22:17
-   |
-LL | impl<T: ?Sized> Trait for W<W<T>>
-   |                 ^^^^^     ^^^^^^^
-LL | where
-LL |     W<T>: Trait,
-   |           ----- unsatisfied trait bound introduced here
-   = note: 8 redundant requirements hidden
-   = note: required for `W<W<W<W<W<W<W<W<W<W<W<_>>>>>>>>>>>` to implement `Trait`
 note: required by a bound in `impls_trait`
   --> $DIR/inductive-fixpoint-hang.rs:28:19
    |
diff --git a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs
index 9d0ea51..7868337 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs
+++ b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.rs
@@ -39,7 +39,7 @@
 
 fn main() {
     impls_a::<()>();
-    //~^ ERROR overflow evaluating the requirement `(): B`
+    //~^ ERROR overflow evaluating the requirement `(): A`
 
     impls_ar::<()>();
     //~^ ERROR overflow evaluating the requirement `(): AR`
diff --git a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr
index fe02d3c..e9cc6bc 100644
--- a/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr
+++ b/tests/ui/traits/next-solver/cycles/inductive-not-on-stack.stderr
@@ -1,25 +1,9 @@
-error[E0275]: overflow evaluating the requirement `(): B`
+error[E0275]: overflow evaluating the requirement `(): A`
   --> $DIR/inductive-not-on-stack.rs:41:15
    |
 LL |     impls_a::<()>();
    |               ^^
    |
-note: required for `()` to implement `A`
-  --> $DIR/inductive-not-on-stack.rs:21:16
-   |
-LL | impl<T: B + C> A for T {}
-   |         -      ^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `B`
-  --> $DIR/inductive-not-on-stack.rs:22:12
-   |
-LL | impl<T: A> B for T {}
-   |         -  ^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 7 redundant requirements hidden
-   = note: required for `()` to implement `A`
 note: required by a bound in `impls_a`
   --> $DIR/inductive-not-on-stack.rs:25:15
    |
@@ -32,29 +16,6 @@
 LL |     impls_ar::<()>();
    |                ^^
    |
-note: required for `()` to implement `BR`
-  --> $DIR/inductive-not-on-stack.rs:35:13
-   |
-LL | impl<T: AR> BR for T {}
-   |         --  ^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `CR`
-  --> $DIR/inductive-not-on-stack.rs:36:13
-   |
-LL | impl<T: BR> CR for T {}
-   |         --  ^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-note: required for `()` to implement `AR`
-  --> $DIR/inductive-not-on-stack.rs:34:18
-   |
-LL | impl<T: CR + BR> AR for T {}
-   |         --       ^^     ^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 6 redundant requirements hidden
-   = note: required for `()` to implement `AR`
 note: required by a bound in `impls_ar`
   --> $DIR/inductive-not-on-stack.rs:38:16
    |
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs
index b90a354..6d75d24 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.rs
@@ -35,5 +35,5 @@
 
 fn main() {
     impls_a::<()>();
-    //~^ ERROR overflow evaluating the requirement `(): CInd`
+    //~^ ERROR overflow evaluating the requirement `(): A`
 }
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr
index 03e61db..17544eb 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-1.stderr
@@ -1,46 +1,9 @@
-error[E0275]: overflow evaluating the requirement `(): CInd`
+error[E0275]: overflow evaluating the requirement `(): A`
   --> $DIR/mixed-cycles-1.rs:37:15
    |
 LL |     impls_a::<()>();
    |               ^^
    |
-note: required for `()` to implement `B`
-  --> $DIR/mixed-cycles-1.rs:31:28
-   |
-LL | impl<T: ?Sized + CInd + C> B for T {}
-   |                  ----      ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-note: required for `()` to implement `C`
-  --> $DIR/mixed-cycles-1.rs:32:25
-   |
-LL | impl<T: ?Sized + B + A> C for T {}
-   |                  -      ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-note: required for `()` to implement `CInd`
-  --> $DIR/mixed-cycles-1.rs:28:21
-   |
-LL | impl<T: ?Sized + C> CInd for T {}
-   |                  -  ^^^^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-   = note: 4 redundant requirements hidden
-   = note: required for `()` to implement `B`
-note: required for `()` to implement `BInd`
-  --> $DIR/mixed-cycles-1.rs:23:21
-   |
-LL | impl<T: ?Sized + B> BInd for T {}
-   |                  -  ^^^^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-note: required for `()` to implement `A`
-  --> $DIR/mixed-cycles-1.rs:30:28
-   |
-LL | impl<T: ?Sized + BInd + C> A for T {}
-   |                  ----      ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
 note: required by a bound in `impls_a`
   --> $DIR/mixed-cycles-1.rs:34:15
    |
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs
index a3ffcaa..c939a6e 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.rs
@@ -28,5 +28,5 @@
 
 fn main() {
     impls_a::<()>();
-    //~^ ERROR overflow evaluating the requirement `(): BInd`
+    //~^ ERROR overflow evaluating the requirement `(): A`
 }
diff --git a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr
index 892426a..a9be101 100644
--- a/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr
+++ b/tests/ui/traits/next-solver/cycles/mixed-cycles-2.stderr
@@ -1,32 +1,9 @@
-error[E0275]: overflow evaluating the requirement `(): BInd`
+error[E0275]: overflow evaluating the requirement `(): A`
   --> $DIR/mixed-cycles-2.rs:30:15
    |
 LL |     impls_a::<()>();
    |               ^^
    |
-note: required for `()` to implement `B`
-  --> $DIR/mixed-cycles-2.rs:25:24
-   |
-LL | impl<T: ?Sized + BInd> B for T {}
-   |                  ----  ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-note: required for `()` to implement `BInd`
-  --> $DIR/mixed-cycles-2.rs:22:21
-   |
-LL | impl<T: ?Sized + B> BInd for T {}
-   |                  -  ^^^^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
-   = note: 6 redundant requirements hidden
-   = note: required for `()` to implement `BInd`
-note: required for `()` to implement `A`
-  --> $DIR/mixed-cycles-2.rs:24:28
-   |
-LL | impl<T: ?Sized + BInd + B> A for T {}
-   |                  ----      ^     ^
-   |                  |
-   |                  unsatisfied trait bound introduced here
 note: required by a bound in `impls_a`
   --> $DIR/mixed-cycles-2.rs:27:15
    |
diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs
new file mode 100644
index 0000000..4094ab8
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Znext-solver
+
+trait Trait {
+    type Assoc;
+}
+
+struct W<T>(*mut T);
+impl<T> Trait for W<W<T>>
+where
+    W<T>: Trait,
+{
+    type Assoc = ();
+}
+
+trait NoOverlap {}
+impl<T: Trait> NoOverlap for T {}
+
+impl<T: Trait<Assoc = u32>> NoOverlap for W<T> {}
+//~^ ERROR conflicting implementations of trait `NoOverlap` for type `W<_>`
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr
new file mode 100644
index 0000000..42be196
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-fail.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `NoOverlap` for type `W<_>`
+  --> $DIR/ambiguous-fail.rs:18:1
+   |
+LL | impl<T: Trait> NoOverlap for T {}
+   | ------------------------------ first implementation here
+LL |
+LL | impl<T: Trait<Assoc = u32>> NoOverlap for W<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs
new file mode 100644
index 0000000..2d40ba3
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.rs
@@ -0,0 +1,21 @@
+//@ compile-flags: -Znext-solver
+
+trait Trait {
+    type Assoc;
+}
+
+struct W<T>(*mut T);
+impl<T> Trait for W<W<T>>
+where
+    W<T>: Trait,
+{
+    type Assoc = ();
+}
+
+trait NoOverlap {}
+impl<T: Trait> NoOverlap for T {}
+
+impl<T: Trait<Assoc = ()>> NoOverlap for W<T> {}
+//~^ ERROR conflicting implementations of trait `NoOverlap` for type `W<_>`
+
+fn main() {}
diff --git a/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr
new file mode 100644
index 0000000..5c77fc7
--- /dev/null
+++ b/tests/ui/traits/next-solver/diagnostics/ambiguous-pass.stderr
@@ -0,0 +1,12 @@
+error[E0119]: conflicting implementations of trait `NoOverlap` for type `W<_>`
+  --> $DIR/ambiguous-pass.rs:18:1
+   |
+LL | impl<T: Trait> NoOverlap for T {}
+   | ------------------------------ first implementation here
+LL |
+LL | impl<T: Trait<Assoc = ()>> NoOverlap for W<T> {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `W<_>`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.rs b/tests/ui/traits/next-solver/issue-118950-root-region.rs
index 8667b3f..9f6dea5 100644
--- a/tests/ui/traits/next-solver/issue-118950-root-region.rs
+++ b/tests/ui/traits/next-solver/issue-118950-root-region.rs
@@ -12,7 +12,7 @@
 trait Overlap<T> {}
 
 type Assoc<'a, T> = <*const T as ToUnit<'a>>::Unit;
-//~^ ERROR: not well-formed
+//~^ ERROR the trait bound `*const T: ToUnit<'a>` is not satisfied
 
 impl<T> Overlap<T> for T {}
 
diff --git a/tests/ui/traits/next-solver/issue-118950-root-region.stderr b/tests/ui/traits/next-solver/issue-118950-root-region.stderr
index 5cb24fa..2e0566c 100644
--- a/tests/ui/traits/next-solver/issue-118950-root-region.stderr
+++ b/tests/ui/traits/next-solver/issue-118950-root-region.stderr
@@ -13,11 +13,17 @@
    = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
    = note: `#[warn(incomplete_features)]` on by default
 
-error: the type `<*const T as ToUnit<'a>>::Unit` is not well-formed
+error[E0277]: the trait bound `*const T: ToUnit<'a>` is not satisfied
   --> $DIR/issue-118950-root-region.rs:14:21
    |
 LL | type Assoc<'a, T> = <*const T as ToUnit<'a>>::Unit;
-   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `ToUnit<'a>` is not implemented for `*const T`
+   |
+help: this trait has no implementations, consider adding one
+  --> $DIR/issue-118950-root-region.rs:8:1
+   |
+LL | trait ToUnit<'a> {
+   | ^^^^^^^^^^^^^^^^
 
 WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }
 WARN rustc_infer::infer::relate::generalize may incompletely handle alias type: AliasTy { args: ['^0.Named(DefId(0:15 ~ issue_118950_root_region[d54f]::{impl#1}::'a), "'a"), ?1t], def_id: DefId(0:8 ~ issue_118950_root_region[d54f]::Assoc) }
@@ -34,5 +40,5 @@
 
 error: aborting due to 3 previous errors; 1 warning emitted
 
-Some errors have detailed explanations: E0119, E0412.
+Some errors have detailed explanations: E0119, E0277, E0412.
 For more information about an error, try `rustc --explain E0119`.
diff --git a/tests/ui/traits/next-solver/member-constraints-in-root-universe.rs b/tests/ui/traits/next-solver/member-constraints-in-root-universe.rs
deleted file mode 100644
index a5696fc..0000000
--- a/tests/ui/traits/next-solver/member-constraints-in-root-universe.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//@ compile-flags: -Znext-solver
-
-trait Trait {
-    type Ty;
-}
-
-impl Trait for for<'a> fn(&'a u8, &'a u8) {
-    type Ty = ();
-}
-
-// argument is necessary to create universes before registering the hidden type.
-fn test<'a>(_: <fn(&u8, &u8) as Trait>::Ty) -> impl Sized {
-    //~^ ERROR the type `<for<'a, 'b> fn(&'a u8, &'b u8) as Trait>::Ty` is not well-formed
-    "hidden type is `&'?0 str` with '?0 member of ['static,]"
-}
-
-fn main() {}
diff --git a/tests/ui/traits/next-solver/member-constraints-in-root-universe.stderr b/tests/ui/traits/next-solver/member-constraints-in-root-universe.stderr
deleted file mode 100644
index 7a9982f..0000000
--- a/tests/ui/traits/next-solver/member-constraints-in-root-universe.stderr
+++ /dev/null
@@ -1,8 +0,0 @@
-error: the type `<for<'a, 'b> fn(&'a u8, &'b u8) as Trait>::Ty` is not well-formed
-  --> $DIR/member-constraints-in-root-universe.rs:12:16
-   |
-LL | fn test<'a>(_: <fn(&u8, &u8) as Trait>::Ty) -> impl Sized {
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: aborting due to 1 previous error
-
diff --git a/tests/ui/traits/next-solver/object-unsafety.rs b/tests/ui/traits/next-solver/object-unsafety.rs
index 3aa1af4..a347984 100644
--- a/tests/ui/traits/next-solver/object-unsafety.rs
+++ b/tests/ui/traits/next-solver/object-unsafety.rs
@@ -10,9 +10,8 @@
 
 pub fn copy_any<T>(t: &T) -> T {
     copy::<dyn Setup<From=T>>(t)
-    //~^ ERROR the type `&<dyn Setup<From = T> as Setup>::From` is not well-formed
+    //~^ ERROR the trait bound `T: Copy` is not satisfied in `dyn Setup<From = T>`
     //~| ERROR mismatched types
-    //~| ERROR the type `<dyn Setup<From = T> as Setup>::From` is not well-formed
     //~| ERROR the trait bound `T: Copy` is not satisfied
 
     // FIXME(-Znext-solver): These error messages are horrible and some of them
diff --git a/tests/ui/traits/next-solver/object-unsafety.stderr b/tests/ui/traits/next-solver/object-unsafety.stderr
index 7c9a607..75d0ce2 100644
--- a/tests/ui/traits/next-solver/object-unsafety.stderr
+++ b/tests/ui/traits/next-solver/object-unsafety.stderr
@@ -15,12 +15,6 @@
 LL | pub fn copy_any<T: std::marker::Copy>(t: &T) -> T {
    |                  +++++++++++++++++++
 
-error: the type `&<dyn Setup<From = T> as Setup>::From` is not well-formed
-  --> $DIR/object-unsafety.rs:12:31
-   |
-LL |     copy::<dyn Setup<From=T>>(t)
-   |                               ^
-
 error[E0308]: mismatched types
   --> $DIR/object-unsafety.rs:12:31
    |
@@ -37,13 +31,19 @@
 LL | fn copy<U: Setup + ?Sized>(from: &U::From) -> U::From {
    |    ^^^^                    --------------
 
-error: the type `<dyn Setup<From = T> as Setup>::From` is not well-formed
+error[E0277]: the trait bound `T: Copy` is not satisfied in `dyn Setup<From = T>`
   --> $DIR/object-unsafety.rs:12:5
    |
 LL |     copy::<dyn Setup<From=T>>(t)
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `dyn Setup<From = T>`, the trait `Copy` is not implemented for `T`, which is required by `dyn Setup<From = T>: Setup`
+   |
+   = note: required because it appears within the type `dyn Setup<From = T>`
+help: consider restricting type parameter `T`
+   |
+LL | pub fn copy_any<T: std::marker::Copy>(t: &T) -> T {
+   |                  +++++++++++++++++++
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
 Some errors have detailed explanations: E0277, E0308.
 For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs
index 052d803..186d0e8 100644
--- a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs
+++ b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.rs
@@ -15,5 +15,5 @@
 
 fn main() {
     impls::<W<_>>();
-    //~^ ERROR overflow evaluating the requirement `_: Sized`
+    //~^ ERROR overflow evaluating the requirement `W<_>: Trait`
 }
diff --git a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr
index 6583cae..b032ae3 100644
--- a/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr
+++ b/tests/ui/traits/next-solver/overflow/exponential-trait-goals.stderr
@@ -1,16 +1,9 @@
-error[E0275]: overflow evaluating the requirement `_: Sized`
+error[E0275]: overflow evaluating the requirement `W<_>: Trait`
   --> $DIR/exponential-trait-goals.rs:17:13
    |
 LL |     impls::<W<_>>();
    |             ^^^^
    |
-note: required for `W<(W<_>, W<_>)>` to implement `Trait`
-  --> $DIR/exponential-trait-goals.rs:7:12
-   |
-LL | impl<T, U> Trait for W<(W<T>, W<U>)>
-   |      -     ^^^^^     ^^^^^^^^^^^^^^^
-   |      |
-   |      unsatisfied trait bound introduced here
 note: required by a bound in `impls`
   --> $DIR/exponential-trait-goals.rs:14:13
    |
diff --git a/tests/ui/traits/next-solver/overflow/global-cache.stderr b/tests/ui/traits/next-solver/overflow/global-cache.stderr
index 9e46772..6761661 100644
--- a/tests/ui/traits/next-solver/overflow/global-cache.stderr
+++ b/tests/ui/traits/next-solver/overflow/global-cache.stderr
@@ -5,15 +5,6 @@
    |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
    = help: consider increasing the recursion limit by adding a `#![recursion_limit = "18"]` attribute to your crate (`global_cache`)
-note: required for `Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<()>>>>>>>>>>>` to implement `Trait`
-  --> $DIR/global-cache.rs:12:16
-   |
-LL | impl<T: Trait> Trait for Inc<T> {}
-   |         -----  ^^^^^     ^^^^^^
-   |         |
-   |         unsatisfied trait bound introduced here
-   = note: 5 redundant requirements hidden
-   = note: required for `Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<Inc<()>>>>>>>>>>>>>>>>` to implement `Trait`
 note: required by a bound in `impls_trait`
   --> $DIR/global-cache.rs:15:19
    |
diff --git a/tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs b/tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs
new file mode 100644
index 0000000..6567f27
--- /dev/null
+++ b/tests/ui/traits/next-solver/typeck/normalize-in-upvar-collection.rs
@@ -0,0 +1,19 @@
+//@ compile-flags: -Znext-solver
+//@ check-pass
+
+// Fixes a regression in icu_provider_adaptors where we weren't normalizing the
+// return type of a function type before performing a `Ty::builtin_deref` call,
+// leading to an ICE.
+
+struct Struct {
+    field: i32,
+}
+
+fn hello(f: impl Fn() -> &'static Box<[i32]>, f2: impl Fn() -> &'static Struct) {
+    let cl = || {
+        let x = &f()[0];
+        let y = &f2().field;
+    };
+}
+
+fn main() {}
diff --git a/tests/ui/transmutability/primitives/bool-mut.rs b/tests/ui/transmutability/primitives/bool-mut.rs
index 5f3f4f3..09b6d58 100644
--- a/tests/ui/transmutability/primitives/bool-mut.rs
+++ b/tests/ui/transmutability/primitives/bool-mut.rs
@@ -1,5 +1,4 @@
 //@ check-fail
-//@[next] compile-flags: -Znext-solver
 
 #![feature(transmutability)]
 mod assert {
diff --git a/tests/ui/transmutability/primitives/bool-mut.stderr b/tests/ui/transmutability/primitives/bool-mut.stderr
index 464c275..a6cf146 100644
--- a/tests/ui/transmutability/primitives/bool-mut.stderr
+++ b/tests/ui/transmutability/primitives/bool-mut.stderr
@@ -1,11 +1,11 @@
 error[E0277]: `u8` cannot be safely transmuted into `bool`
-  --> $DIR/bool-mut.rs:15:50
+  --> $DIR/bool-mut.rs:14:50
    |
 LL |     assert::is_transmutable::<&'static mut bool, &'static mut u8>()
    |                                                  ^^^^^^^^^^^^^^^ at least one value of `u8` isn't a bit-valid value of `bool`
    |
 note: required by a bound in `is_transmutable`
-  --> $DIR/bool-mut.rs:10:14
+  --> $DIR/bool-mut.rs:9:14
    |
 LL |     pub fn is_transmutable<Src, Dst>()
    |            --------------- required by a bound in this function
diff --git a/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs b/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs
index 0e1d44e..75a4fbd 100644
--- a/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs
+++ b/tests/ui/type-alias-impl-trait/defined-by-user-annotation.rs
@@ -1,4 +1,4 @@
-// User type annotation in fn bodies is a a valid defining site for opaque types.
+// User type annotation in fn bodies is a valid defining site for opaque types.
 //@ check-pass
 #![feature(type_alias_impl_trait)]
 
diff --git a/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs b/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs
index 59ba269..b209b4b 100644
--- a/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs
+++ b/tests/ui/type-alias-impl-trait/equal-lifetime-params-not-ok.rs
@@ -25,7 +25,7 @@
 }
 
 // This is similar to the previous cases in that 'a is equal to 'static,
-// which is is some sense an implicit parameter to `Opaque`.
+// which is some sense an implicit parameter to `Opaque`.
 // For example, given a defining use `Opaque<'a> := &'a ()`,
 // it is ambiguous whether `Opaque<'a> := &'a ()` or `Opaque<'a> := &'static ()`
 mod mod4 {
diff --git a/tests/ui/type-alias-impl-trait/issue-60662.stdout b/tests/ui/type-alias-impl-trait/issue-60662.stdout
index e643dba..b541cbe 100644
--- a/tests/ui/type-alias-impl-trait/issue-60662.stdout
+++ b/tests/ui/type-alias-impl-trait/issue-60662.stdout
@@ -10,5 +10,5 @@
 trait Animal { }
 
 fn main() {
-        type ServeFut = /*impl Trait*/;
-    }
+    type ServeFut = /*impl Trait*/;
+}
diff --git a/tests/ui/type-alias-impl-trait/static-lifetime-through-closure-issue-122775.rs b/tests/ui/type-alias-impl-trait/static-lifetime-through-closure-issue-122775.rs
new file mode 100644
index 0000000..1bb0acf
--- /dev/null
+++ b/tests/ui/type-alias-impl-trait/static-lifetime-through-closure-issue-122775.rs
@@ -0,0 +1,17 @@
+//@ check-pass
+
+#![feature(type_alias_impl_trait)]
+
+fn spawn<T, F>(future: F) -> impl Sized
+where
+    F: FnOnce() -> T,
+{
+    future
+}
+
+fn spawn_task(sender: &'static ()) -> impl Sized {
+    type Tait = impl Sized + 'static;
+    spawn::<Tait, _>(move || sender)
+}
+
+fn main() {}
diff --git a/tests/ui/type/pattern_types/range_patterns_usage.rs b/tests/ui/type/pattern_types/range_patterns_usage.rs
index 7fe5042..2a9f736 100644
--- a/tests/ui/type/pattern_types/range_patterns_usage.rs
+++ b/tests/ui/type/pattern_types/range_patterns_usage.rs
@@ -8,7 +8,7 @@
 
 use std::pat::pattern_type;
 
-type X = std::num::NonZeroU32;
+type X = std::num::NonZero<u32>;
 type Y = pattern_type!(u32 is 1..);
 type Z = Option<pattern_type!(u32 is 1..)>;
 struct NonZeroU32New(pattern_type!(u32 is 1..));
diff --git a/tests/ui/typeck/issue-81943.stderr b/tests/ui/typeck/issue-81943.stderr
index 041ff10..f8da9ef 100644
--- a/tests/ui/typeck/issue-81943.stderr
+++ b/tests/ui/typeck/issue-81943.stderr
@@ -2,7 +2,9 @@
   --> $DIR/issue-81943.rs:7:9
    |
 LL |   f(|x| lib::d!(x));
-   |         ^^^^^^^^^^ expected `()`, found `i32`
+   |        -^^^^^^^^^^ expected `()`, found `i32`
+   |        |
+   |        help: try adding a return type: `-> i32`
    |
    = note: this error originates in the macro `lib::d` (in Nightly builds, run with -Z macro-backtrace for more info)
 
@@ -10,28 +12,22 @@
   --> $DIR/issue-81943.rs:8:28
    |
 LL |   f(|x| match x { tmp => { g(tmp) } });
-   |         -------------------^^^^^^----
-   |         |                  |
-   |         |                  expected `()`, found `i32`
-   |         expected this to be `()`
+   |                            ^^^^^^ expected `()`, found `i32`
    |
 help: consider using a semicolon here
    |
 LL |   f(|x| match x { tmp => { g(tmp); } });
    |                                  +
-help: consider using a semicolon here
+help: try adding a return type
    |
-LL |   f(|x| match x { tmp => { g(tmp) } };);
-   |                                      +
+LL |   f(|x| -> i32 match x { tmp => { g(tmp) } });
+   |         ++++++
 
 error[E0308]: mismatched types
   --> $DIR/issue-81943.rs:10:38
    |
 LL |     ($e:expr) => { match $e { x => { g(x) } } }
-   |                    ------------------^^^^----
-   |                    |                 |
-   |                    |                 expected `()`, found `i32`
-   |                    expected this to be `()`
+   |                                      ^^^^ expected `()`, found `i32`
 LL |   }
 LL |   f(|x| d!(x));
    |         ----- in this macro invocation
@@ -41,10 +37,10 @@
    |
 LL |     ($e:expr) => { match $e { x => { g(x); } } }
    |                                          +
-help: consider using a semicolon here
+help: try adding a return type
    |
-LL |     ($e:expr) => { match $e { x => { g(x) } }; }
-   |                                              +
+LL |   f(|x| -> i32 d!(x));
+   |         ++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/unop-move-semantics.rs b/tests/ui/unop/unop-move-semantics.rs
similarity index 100%
rename from tests/ui/unop-move-semantics.rs
rename to tests/ui/unop/unop-move-semantics.rs
diff --git a/tests/ui/unop-move-semantics.stderr b/tests/ui/unop/unop-move-semantics.stderr
similarity index 100%
rename from tests/ui/unop-move-semantics.stderr
rename to tests/ui/unop/unop-move-semantics.stderr
diff --git a/tests/ui/unop-neg-bool.rs b/tests/ui/unop/unop-neg-bool.rs
similarity index 100%
rename from tests/ui/unop-neg-bool.rs
rename to tests/ui/unop/unop-neg-bool.rs
diff --git a/tests/ui/unop-neg-bool.stderr b/tests/ui/unop/unop-neg-bool.stderr
similarity index 100%
rename from tests/ui/unop-neg-bool.stderr
rename to tests/ui/unop/unop-neg-bool.stderr
diff --git a/tests/ui/unpretty/auxiliary/data.txt b/tests/ui/unpretty/auxiliary/data.txt
new file mode 100644
index 0000000..2f62e46
--- /dev/null
+++ b/tests/ui/unpretty/auxiliary/data.txt
@@ -0,0 +1 @@
+data for include_bytes in ../expanded-exhaustive.rs
diff --git a/tests/ui/unpretty/bad-literal.stdout b/tests/ui/unpretty/bad-literal.stdout
index 07ecb99..c527271 100644
--- a/tests/ui/unpretty/bad-literal.stdout
+++ b/tests/ui/unpretty/bad-literal.stdout
@@ -7,5 +7,5 @@
 
 // In #100948 this caused an ICE with -Zunpretty=hir.
 fn main() {
-        <bad-literal>;
-    }
+    <bad-literal>;
+}
diff --git a/tests/ui/unpretty/box.stdout b/tests/ui/unpretty/box.stdout
index 0fd51ed..e3b9b9a 100644
--- a/tests/ui/unpretty/box.stdout
+++ b/tests/ui/unpretty/box.stdout
@@ -8,7 +8,7 @@
 extern crate std;
 
 fn main() {
-        let _ =
-            #[rustc_box]
-            Box::new(1);
-    }
+    let _ =
+        #[rustc_box]
+        Box::new(1);
+}
diff --git a/tests/ui/unpretty/expanded-exhaustive.rs b/tests/ui/unpretty/expanded-exhaustive.rs
new file mode 100644
index 0000000..6aa032d
--- /dev/null
+++ b/tests/ui/unpretty/expanded-exhaustive.rs
@@ -0,0 +1,888 @@
+//@ compile-flags: -Zunpretty=expanded -Zunstable-options
+//@ edition:2024
+//@ check-pass
+
+#![feature(async_closure)]
+#![feature(auto_traits)]
+#![feature(box_patterns)]
+#![feature(builtin_syntax)]
+#![feature(concat_idents)]
+#![feature(const_trait_impl)]
+#![feature(core_pattern_type)]
+#![feature(decl_macro)]
+#![feature(deref_patterns)]
+#![feature(explicit_tail_calls)]
+#![feature(gen_blocks)]
+#![feature(let_chains)]
+#![feature(more_qualified_paths)]
+#![feature(never_patterns)]
+#![feature(never_type)]
+#![feature(pattern_types)]
+#![feature(prelude_import)]
+#![feature(raw_ref_op)]
+#![feature(specialization)]
+#![feature(trace_macros)]
+#![feature(trait_alias)]
+#![feature(try_blocks)]
+#![feature(unnamed_fields)]
+#![feature(yeet_expr)]
+#![allow(incomplete_features)]
+
+#[prelude_import]
+use self::prelude::*;
+
+mod prelude {
+    pub use std::prelude::rust_2024::*;
+
+    pub type T = _;
+
+    pub trait Trait {
+        const CONST: ();
+    }
+}
+
+mod attributes {
+    //! inner single-line doc comment
+    /*!
+     * inner multi-line doc comment
+     */
+    #![doc = "inner doc attribute"]
+    #![allow(dead_code, unused_variables)]
+    #![no_std]
+
+    /// outer single-line doc comment
+    /**
+     * outer multi-line doc comment
+     */
+    #[doc = "outer doc attribute"]
+    #[doc = concat!("mac", "ro")]
+    #[allow()]
+    #[repr(C)]
+    struct Struct;
+}
+
+mod expressions {
+    /// ExprKind::Array
+    fn expr_array() {
+        [];
+        [true];
+        [true,];
+        [true, true];
+        ["long........................................................................"];
+        ["long............................................................", true];
+    }
+
+    /// ExprKind::ConstBlock
+    fn expr_const_block() {
+        const {};
+        const { 1 };
+        const { struct S; };
+    }
+
+    /// ExprKind::Call
+    fn expr_call() {
+        let f;
+        f();
+        f::<u8>();
+        f::<1>();
+        f::<'static, u8, 1>();
+        f(true);
+        f(true,);
+        ()();
+    }
+
+    /// ExprKind::MethodCall
+    fn expr_method_call() {
+        let x;
+        x.f();
+        x.f::<u8>();
+        x.collect::<Vec<_>>();
+    }
+
+    /// ExprKind::Tup
+    fn expr_tup() {
+        ();
+        (true,);
+        (true, false);
+        (true, false,);
+    }
+
+    /// ExprKind::Binary
+    fn expr_binary() {
+        let (a, b, c, d, x, y);
+        true || false;
+        true || false && false;
+        a < 1 && 2 < b && c > 3 && 4 > d;
+        a & b & !c;
+        a + b * c - d + -1 * -2 - -3;
+        x = !y;
+    }
+
+    /// ExprKind::Unary
+    fn expr_unary() {
+        let expr;
+        *expr;
+        !expr;
+        -expr;
+    }
+
+    /// ExprKind::Lit
+    fn expr_lit() {
+        'x';
+        1_000_i8;
+        1.00000000000000000000001;
+    }
+
+    /// ExprKind::Cast
+    fn expr_cast() {
+        let expr;
+        expr as T;
+        expr as T<u8>;
+    }
+
+    /// ExprKind::Type
+    fn expr_type() {
+        let expr;
+        builtin # type_ascribe(expr, T);
+    }
+
+    /// ExprKind::Let
+    fn expr_let() {
+        let b;
+        if let Some(a) = b {}
+        if let _ = true && false {}
+        if let _ = (true && false) {}
+    }
+
+    /// ExprKind::If
+    fn expr_if() {
+        if true {}
+        if !true {}
+        if let true = true {} else {}
+        if true {} else if false {}
+        if true {} else if false {} else {}
+        if true { return; } else if false { 0 } else { 0 }
+    }
+
+    /// ExprKind::While
+    fn expr_while() {
+        while false {}
+        'a: while false {}
+        while let true = true {}
+    }
+
+    /// ExprKind::ForLoop
+    fn expr_for_loop() {
+        let x;
+        for _ in x {}
+        'a: for _ in x {}
+    }
+
+    /// ExprKind::Loop
+    fn expr_loop() {
+        loop {}
+        'a: loop {}
+    }
+
+    /// ExprKind::Match
+    fn expr_match() {
+        let value;
+        match value {}
+        match value { ok => 1 }
+        match value {
+            ok => 1,
+            err => 0,
+        }
+    }
+
+    /// ExprKind::Closure
+    fn expr_closure() {
+        let value;
+        || {};
+        |x| {};
+        |x: u8| {};
+        || ();
+        move || value;
+        async || value;
+        async move || value;
+        static || value;
+        static move || value;
+        (static async || value);
+        (static async move || value);
+        || -> u8 { value };
+        1 + || {};
+    }
+
+    /// ExprKind::Block
+    fn expr_block() {
+        {}
+        unsafe {}
+        'a: {}
+        #[allow()] {}
+        { #![allow()] }
+    }
+
+    /// ExprKind::Gen
+    fn expr_gen() {
+        async {};
+        async move {};
+        gen {};
+        gen move {};
+        async gen {};
+        async gen move {};
+    }
+
+    /// ExprKind::Await
+    fn expr_await() {
+        let fut;
+        fut.await;
+    }
+
+    /// ExprKind::TryBlock
+    fn expr_try_block() {
+        try {}
+        try { return; }
+    }
+
+    /// ExprKind::Assign
+    fn expr_assign() {
+        let expr;
+        expr = true;
+    }
+
+    /// ExprKind::AssignOp
+    fn expr_assign_op() {
+        let expr;
+        expr += true;
+    }
+
+    /// ExprKind::Field
+    fn expr_field() {
+        let expr;
+        expr.field;
+        expr.0;
+    }
+
+    /// ExprKind::Index
+    fn expr_index() {
+        let expr;
+        expr[true];
+    }
+
+    /// ExprKind::Range
+    fn expr_range() {
+        let (lo, hi);
+        ..;
+        ..hi;
+        lo..;
+        lo..hi;
+        lo .. hi;
+        ..=hi;
+        lo..=hi;
+        -2..=-1;
+    }
+
+    /// ExprKind::Underscore
+    fn expr_underscore() {
+        _;
+    }
+
+    /// ExprKind::Path
+    fn expr_path() {
+        let x;
+        crate::expressions::expr_path;
+        crate::expressions::expr_path::<'static>;
+        <T as Default>::default;
+        <T as ::core::default::Default>::default::<>;
+        x::();
+        x::(T, T) -> T;
+        crate::() -> ()::expressions::() -> ()::expr_path;
+        core::()::marker::()::PhantomData;
+    }
+
+    /// ExprKind::AddrOf
+    fn expr_addr_of() {
+        let expr;
+        &expr;
+        &mut expr;
+        &raw const expr;
+        &raw mut expr;
+    }
+
+    /// ExprKind::Break
+    fn expr_break() {
+        'a: {
+            break;
+            break 'a;
+            break true;
+            break 'a true;
+        }
+    }
+
+    /// ExprKind::Continue
+    fn expr_continue() {
+        'a: {
+            continue;
+            continue 'a;
+        }
+    }
+
+    /// ExprKind::Ret
+    fn expr_ret() {
+        return;
+        return true;
+    }
+
+    /// ExprKind::InlineAsm
+    fn expr_inline_asm() {
+        let x;
+        core::arch::asm!(
+            "mov {tmp}, {x}",
+            "shl {tmp}, 1",
+            "shl {x}, 2",
+            "add {x}, {tmp}",
+            x = inout(reg) x,
+            tmp = out(reg) _,
+        );
+    }
+
+    /// ExprKind::OffsetOf
+    fn expr_offset_of() {
+        core::mem::offset_of!(T, field);
+    }
+
+    /// ExprKind::MacCall
+    fn expr_mac_call() {
+        stringify!(...);
+        stringify![...];
+        stringify! { ... };
+    }
+
+    /// ExprKind::Struct
+    fn expr_struct() {
+        struct Struct {}
+        let (x, base);
+        Struct {};
+        <Struct as ToOwned>::Owned {};
+        Struct { .. };
+        Struct { .. base };
+        Struct { x };
+        Struct { x, ..base };
+        Struct { x: true };
+        Struct { x: true, .. };
+        Struct { x: true, ..base };
+        Struct { 0: true, ..base };
+    }
+
+    /// ExprKind::Repeat
+    fn expr_repeat() {
+        [(); 0];
+    }
+
+    /// ExprKind::Paren
+    fn expr_paren() {
+        let expr;
+        (expr);
+    }
+
+    /// ExprKind::Try
+    fn expr_try() {
+        let expr;
+        expr?;
+    }
+
+    /// ExprKind::Yield
+    fn expr_yield() {
+        yield;
+        yield true;
+    }
+
+    /// ExprKind::Yeet
+    fn expr_yeet() {
+        do yeet;
+        do yeet 0;
+    }
+
+    /// ExprKind::Become
+    fn expr_become() {
+        become true;
+    }
+
+    /// ExprKind::IncludedBytes
+    fn expr_include_bytes() {
+        include_bytes!("auxiliary/data.txt");
+    }
+
+    /// ExprKind::FormatArgs
+    fn expr_format_args() {
+        let expr;
+        format_args!("");
+        format_args!("{}", expr);
+    }
+}
+
+mod items {
+    /// ItemKind::ExternCrate
+    mod item_extern_crate {
+        extern crate core;
+        extern crate self as unpretty;
+        pub extern crate core as _;
+    }
+
+    /// ItemKind::Use
+    mod item_use {
+        use crate::{expressions, items::item_use};
+        pub use core::*;
+    }
+
+    /// ItemKind::Static
+    mod item_static {
+        pub static A: () = {};
+        static mut B: () = {};
+    }
+
+    /// ItemKind::Const
+    mod item_const {
+        pub const A: () = {};
+
+        trait TraitItems {
+            const B: ();
+            const C: () = {};
+        }
+    }
+
+    /// ItemKind::Fn
+    mod item_fn {
+        pub const unsafe extern "C" fn f() {}
+        pub async unsafe extern fn g() {}
+        fn h<'a, T>() where T: 'a {}
+
+        trait TraitItems {
+            unsafe extern fn f();
+        }
+
+        impl TraitItems for _ {
+            default unsafe extern fn f() {}
+        }
+    }
+
+    /// ItemKind::Mod
+    mod item_mod {
+        // ...
+    }
+
+    /// ItemKind::ForeignMod
+    mod item_foreign_mod {
+        extern "C++" {}
+        extern {}
+    }
+
+    /// ItemKind::GlobalAsm
+    mod item_global_asm {
+        core::arch::global_asm!(".globl my_asm_func");
+    }
+
+    /// ItemKind::TyAlias
+    mod item_ty_alias {
+        pub type Type<'a> where T: 'a, = T;
+    }
+
+    /// ItemKind::Enum
+    mod item_enum {
+        pub enum Void {}
+        enum Empty {
+            Unit,
+            Tuple(),
+            Struct {},
+        }
+        enum Generic<'a, T>
+        where
+            T: 'a,
+        {
+            Tuple(T),
+            Struct { t: T },
+        }
+    }
+
+    /// ItemKind::Struct
+    mod item_struct {
+        pub struct Unit;
+        struct Tuple();
+        struct Newtype(Unit);
+        struct Struct {}
+        struct Generic<'a, T>
+        where
+            T: 'a,
+        {
+            t: T,
+        }
+    }
+
+    /// ItemKind::Union
+    mod item_union {
+        union Generic<'a, T>
+        where
+            T: 'a,
+        {
+            t: T,
+        }
+    }
+
+    /// ItemKind::Trait
+    mod item_trait {
+        pub unsafe auto trait Send {}
+        trait Trait<'a>: Sized
+        where
+            Self: 'a,
+        {
+        }
+    }
+
+    /// ItemKind::TraitAlias
+    mod item_trait_alias {
+        pub trait Trait<T> = Sized where for<'a> T: 'a;
+    }
+
+    /// ItemKind::Impl
+    mod item_impl {
+        impl () {}
+        impl<T> () {}
+        impl Default for () {}
+        impl<T> const Default for () {}
+    }
+
+    /// ItemKind::MacCall
+    mod item_mac_call {
+        trace_macros!(false);
+        trace_macros![false];
+        trace_macros! { false }
+    }
+
+    /// ItemKind::MacroDef
+    mod item_macro_def {
+        macro_rules! mac { () => {...}; }
+        pub macro stringify() {}
+    }
+
+    /// ItemKind::Delegation
+    mod item_delegation {
+        /*! FIXME: todo */
+    }
+
+    /// ItemKind::DelegationMac
+    mod item_delegation_mac {
+        /*! FIXME: todo */
+    }
+}
+
+mod patterns {
+    /// PatKind::Wild
+    fn pat_wild() {
+        let _;
+    }
+
+    /// PatKind::Ident
+    fn pat_ident() {
+        let x;
+        let ref x;
+        let mut x;
+        let ref mut x;
+        let ref mut x @ _;
+    }
+
+    /// PatKind::Struct
+    fn pat_struct() {
+        let T {};
+        let T::<T> {};
+        let T::<'static> {};
+        let T { x };
+        let T { x: _x };
+        let T { .. };
+        let T { x, .. };
+        let T { x: _x, .. };
+        let T { 0: _x, .. };
+        let <T as ToOwned>::Owned {};
+    }
+
+    /// PatKind::TupleStruct
+    fn pat_tuple_struct() {
+        struct Tuple();
+        let Tuple();
+        let Tuple::<T>();
+        let Tuple::<'static>();
+        let Tuple(x);
+        let Tuple(..);
+        let Tuple(x, ..);
+    }
+
+    /// PatKind::Or
+    fn pat_or() {
+        let (true | false);
+        let (| true);
+        let (|true| false);
+    }
+
+    /// PatKind::Path
+    fn pat_path() {
+        let core::marker::PhantomData;
+        let core::marker::PhantomData::<T>;
+        let core::marker::PhantomData::<'static>;
+        let <T as Trait>::CONST;
+    }
+
+    /// PatKind::Tuple
+    fn pat_tuple() {
+        let ();
+        let (true,);
+        let (true, false);
+    }
+
+    /// PatKind::Box
+    fn pat_box() {
+        let box pat;
+    }
+
+    /// PatKind::Deref
+    fn pat_deref() {
+        let deref!(pat);
+    }
+
+    /// PatKind::Ref
+    fn pat_ref() {
+        let &pat;
+        let &mut pat;
+    }
+
+    /// PatKind::Lit
+    fn pat_lit() {
+        let 1_000_i8;
+        let -"";
+    }
+
+    /// PatKind::Range
+    fn pat_range() {
+        let ..1;
+        let 0..;
+        let 0..1;
+        let 0..=1;
+        let -2..=-1;
+    }
+
+    /// PatKind::Slice
+    fn pat_slice() {
+        let [];
+        let [true];
+        let [true,];
+        let [true, false];
+    }
+
+    /// PatKind::Rest
+    fn pat_rest() {
+        let ..;
+    }
+
+    /// PatKind::Never
+    fn pat_never() {
+        let !;
+        let Some(!);
+    }
+
+    /// PatKind::Paren
+    fn pat_paren() {
+        let (pat);
+    }
+
+    /// PatKind::MacCall
+    fn pat_mac_call() {
+        let stringify!();
+        let stringify![];
+        let stringify! {};
+    }
+}
+
+mod statements {
+    /// StmtKind::Let
+    fn stmt_let() {
+        let _;
+        let _ = true;
+        let _: T = true;
+        let _ = true else { return; };
+    }
+
+    /// StmtKind::Item
+    fn stmt_item() {
+        struct Struct {}
+        struct Unit;
+    }
+
+    /// StmtKind::Expr
+    fn stmt_expr() {
+        ()
+    }
+
+    /// StmtKind::Semi
+    fn stmt_semi() {
+        1 + 1;
+    }
+
+    /// StmtKind::Empty
+    fn stmt_empty() {
+        ;
+    }
+
+    /// StmtKind::MacCall
+    fn stmt_mac_call() {
+        stringify!(...);
+        stringify![...];
+        stringify! { ... };
+    }
+}
+
+mod types {
+    /// TyKind::Slice
+    fn ty_slice() {
+        let _: [T];
+    }
+
+    /// TyKind::Array
+    fn ty_array() {
+        let _: [T; 0];
+    }
+
+    /// TyKind::Ptr
+    fn ty_ptr() {
+        let _: *const T;
+        let _: *mut T;
+    }
+
+    /// TyKind::Ref
+    fn ty_ref() {
+        let _: &T;
+        let _: &mut T;
+        let _: &'static T;
+        let _: &'static mut [T];
+        let _: &T<T<T<T<T>>>>;
+        let _: &T<T<T<T<T> > > >;
+    }
+
+    /// TyKind::BareFn
+    fn ty_bare_fn() {
+        let _: fn();
+        let _: fn() -> ();
+        let _: fn(T);
+        let _: fn(t: T);
+        let _: for<> fn();
+        let _: for<'a> fn();
+    }
+
+    /// TyKind::Never
+    fn ty_never() {
+        let _: !;
+    }
+
+    /// TyKind::Tup
+    fn ty_tup() {
+        let _: ();
+        let _: (T,);
+        let _: (T, T);
+    }
+
+    /// TyKind::AnonStruct
+    fn ty_anon_struct() {
+        struct Struct {
+            _: struct { t: T },
+        }
+    }
+
+    /// TyKind::AnonUnion
+    fn ty_anon_union() {
+        struct Struct {
+            _: union { t: T },
+        }
+    }
+
+    /// TyKind::Path
+    fn ty_path() {
+        let _: T;
+        let _: T<'static>;
+        let _: T<T>;
+        let _: T::<T>;
+        let _: T() -> !;
+        let _: <T as ToOwned>::Owned;
+    }
+
+    /// TyKind::TraitObject
+    fn ty_trait_object() {
+        let _: dyn Send;
+        let _: dyn Send + 'static;
+        let _: dyn 'static + Send;
+        let _: dyn for<'a> Send;
+    }
+
+    /// TyKind::ImplTrait
+    const fn ty_impl_trait() {
+        let _: impl Send;
+        let _: impl Send + 'static;
+        let _: impl 'static + Send;
+        let _: impl ?Sized;
+        let _: impl ~const Clone;
+        let _: impl for<'a> Send;
+    }
+
+    /// TyKind::Paren
+    fn ty_paren() {
+        let _: (T);
+    }
+
+    /// TyKind::Typeof
+    fn ty_typeof() {
+        /*! unused for now */
+    }
+
+    /// TyKind::Infer
+    fn ty_infer() {
+        let _: _;
+    }
+
+    /// TyKind::ImplicitSelf
+    fn ty_implicit_self() {
+        /*! there is no syntax for this */
+    }
+
+    /// TyKind::MacCall
+    fn ty_mac_call() {
+        let _: concat_idents!(T);
+        let _: concat_idents![T];
+        let _: concat_idents! { T };
+    }
+
+    /// TyKind::CVarArgs
+    fn ty_c_var_args() {
+        /*! FIXME: todo */
+    }
+
+    /// TyKind::Pat
+    fn ty_pat() {
+        let _: core::pattern_type!(u32 is 1..);
+    }
+}
+
+mod visibilities {
+    /// VisibilityKind::Public
+    mod visibility_public {
+        pub struct Pub;
+    }
+
+    /// VisibilityKind::Restricted
+    mod visibility_restricted {
+        pub(crate) struct PubCrate;
+        pub(self) struct PubSelf;
+        pub(super) struct PubSuper;
+        pub(in crate) struct PubInCrate;
+        pub(in self) struct PubInSelf;
+        pub(in super) struct PubInSuper;
+        pub(in crate::visibilities) struct PubInCrateVisibilities;
+        pub(in self::super) struct PubInSelfSuper;
+        pub(in super::visibility_restricted) struct PubInSuperMod;
+    }
+}
diff --git a/tests/ui/unpretty/expanded-exhaustive.stdout b/tests/ui/unpretty/expanded-exhaustive.stdout
new file mode 100644
index 0000000..325bace
--- /dev/null
+++ b/tests/ui/unpretty/expanded-exhaustive.stdout
@@ -0,0 +1,719 @@
+#![feature(prelude_import)]
+//@ compile-flags: -Zunpretty=expanded -Zunstable-options
+//@ edition:2024
+//@ check-pass
+
+#![feature(async_closure)]
+#![feature(auto_traits)]
+#![feature(box_patterns)]
+#![feature(builtin_syntax)]
+#![feature(concat_idents)]
+#![feature(const_trait_impl)]
+#![feature(core_pattern_type)]
+#![feature(decl_macro)]
+#![feature(deref_patterns)]
+#![feature(explicit_tail_calls)]
+#![feature(gen_blocks)]
+#![feature(let_chains)]
+#![feature(more_qualified_paths)]
+#![feature(never_patterns)]
+#![feature(never_type)]
+#![feature(pattern_types)]
+#![feature(prelude_import)]
+#![feature(raw_ref_op)]
+#![feature(specialization)]
+#![feature(trace_macros)]
+#![feature(trait_alias)]
+#![feature(try_blocks)]
+#![feature(unnamed_fields)]
+#![feature(yeet_expr)]
+#![allow(incomplete_features)]
+#[prelude_import]
+use std::prelude::rust_2024::*;
+#[macro_use]
+extern crate std;
+
+#[prelude_import]
+use self::prelude::*;
+
+mod prelude {
+    pub use std::prelude::rust_2024::*;
+
+    pub type T = _;
+
+    pub trait Trait {
+        const CONST: ();
+    }
+}
+
+mod attributes {
+    //! inner single-line doc comment
+    /*!
+     * inner multi-line doc comment
+     */
+    #![doc = "inner doc attribute"]
+    #![allow(dead_code, unused_variables)]
+    #![no_std]
+
+    /// outer single-line doc comment
+    /**
+     * outer multi-line doc comment
+     */
+    #[doc = "outer doc attribute"]
+    #[doc = "macro"]
+    #[allow()]
+    #[repr(C)]
+    struct Struct;
+}
+
+mod expressions {
+    /// ExprKind::Array
+    fn expr_array() {
+        [];
+        [true];
+        [true];
+        [true, true];
+        ["long........................................................................"];
+        ["long............................................................",
+                true];
+    }
+
+    /// ExprKind::ConstBlock
+    fn expr_const_block() {
+        const {};
+        const { 1 };
+        const {
+                struct S;
+            };
+    }
+
+    /// ExprKind::Call
+    fn expr_call() {
+        let f;
+        f();
+        f::<u8>();
+        f::<1>();
+        f::<'static, u8, 1>();
+        f(true);
+        f(true);
+        ()();
+    }
+
+    /// ExprKind::MethodCall
+    fn expr_method_call() {
+        let x;
+        x.f();
+        x.f::<u8>();
+        x.collect::<Vec<_>>();
+    }
+
+    /// ExprKind::Tup
+    fn expr_tup() { (); (true,); (true, false); (true, false); }
+
+    /// ExprKind::Binary
+    fn expr_binary() {
+        let (a, b, c, d, x, y);
+        true || false;
+        true || false && false;
+        a < 1 && 2 < b && c > 3 && 4 > d;
+        a & b & !c;
+        a + b * c - d + -1 * -2 - -3;
+        x = !y;
+    }
+
+    /// ExprKind::Unary
+    fn expr_unary() { let expr; *expr; !expr; -expr; }
+
+    /// ExprKind::Lit
+    fn expr_lit() { 'x'; 1_000_i8; 1.00000000000000000000001; }
+
+    /// ExprKind::Cast
+    fn expr_cast() { let expr; expr as T; expr as T<u8>; }
+
+    /// ExprKind::Type
+    fn expr_type() { let expr; builtin # type_ascribe(expr, T); }
+
+    /// ExprKind::Let
+    fn expr_let() {
+        let b;
+        if let Some(a) = b {}
+        if let _ = true && false {}
+        if let _ = (true && false) {}
+    }
+
+    /// ExprKind::If
+    fn expr_if() {
+        if true {}
+        if !true {}
+        if let true = true {} else {}
+        if true {} else if false {}
+        if true {} else if false {} else {}
+        if true { return; } else if false { 0 } else { 0 }
+    }
+
+    /// ExprKind::While
+    fn expr_while() {
+        while false {}
+        'a: while false {}
+        while let true = true {}
+    }
+
+    /// ExprKind::ForLoop
+    fn expr_for_loop() { let x; for _ in x {} 'a: for _ in x {} }
+
+    /// ExprKind::Loop
+    fn expr_loop() { loop {} 'a: loop {} }
+
+    /// ExprKind::Match
+    fn expr_match() {
+        let value;
+        match value {}
+        match value { ok => 1, }
+        match value { ok => 1, err => 0, }
+    }
+
+    /// ExprKind::Closure
+    fn expr_closure() {
+        let value;
+        || {};
+        |x| {};
+        |x: u8| {};
+        || ();
+        move || value;
+        async || value;
+        async move || value;
+        static || value;
+        static move || value;
+        (static async || value);
+        (static async move || value);
+        || -> u8 { value };
+        1 + (|| {});
+    }
+
+    /// ExprKind::Block
+    fn expr_block() {
+        {}
+        unsafe {}
+        'a: {}
+
+        #[allow()]
+        {}
+        {
+            #![allow()]
+        }
+    }
+
+    /// ExprKind::Gen
+    fn expr_gen() {
+        async {};
+        async move {};
+        gen {};
+        gen move {};
+        async gen {};
+        async gen move {};
+    }
+
+    /// ExprKind::Await
+    fn expr_await() { let fut; fut.await; }
+
+    /// ExprKind::TryBlock
+    fn expr_try_block() { try {} try { return; } }
+
+    /// ExprKind::Assign
+    fn expr_assign() { let expr; expr = true; }
+
+    /// ExprKind::AssignOp
+    fn expr_assign_op() { let expr; expr += true; }
+
+    /// ExprKind::Field
+    fn expr_field() { let expr; expr.field; expr.0; }
+
+    /// ExprKind::Index
+    fn expr_index() { let expr; expr[true]; }
+
+    /// ExprKind::Range
+    fn expr_range() {
+        let (lo, hi);
+        ..;
+        ..hi;
+        lo..;
+        lo..hi;
+        lo..hi;
+        ..=hi;
+        lo..=hi;
+        -2..=-1;
+    }
+
+    /// ExprKind::Underscore
+    fn expr_underscore() { _; }
+
+    /// ExprKind::Path
+    fn expr_path() {
+        let x;
+        crate::expressions::expr_path;
+        crate::expressions::expr_path::<'static>;
+        <T as Default>::default;
+        <T as ::core::default::Default>::default::<>;
+        x::();
+        x::(T, T) -> T;
+        crate::() -> ()::expressions::() -> ()::expr_path;
+        core::()::marker::()::PhantomData;
+    }
+
+    /// ExprKind::AddrOf
+    fn expr_addr_of() {
+        let expr;
+        &expr;
+        &mut expr;
+        &raw const expr;
+        &raw mut expr;
+    }
+
+    /// ExprKind::Break
+    fn expr_break() { 'a: { break; break 'a; break true; break 'a true; } }
+
+    /// ExprKind::Continue
+    fn expr_continue() { 'a: { continue; continue 'a; } }
+
+    /// ExprKind::Ret
+    fn expr_ret() { return; return true; }
+
+    /// ExprKind::InlineAsm
+    fn expr_inline_asm() {
+        let x;
+        asm!("mov {1}, {0}\nshl {1}, 1\nshl {0}, 2\nadd {0}, {1}",
+            inout(reg)
+            x,
+            out(reg)
+            _);
+    }
+
+    /// ExprKind::OffsetOf
+    fn expr_offset_of() {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        // ...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+        { builtin # offset_of(T, field) };
+    }
+    /// ExprKind::MacCall
+    fn expr_mac_call() { "..."; "..."; "..."; }
+    /// ExprKind::Struct
+    fn expr_struct() {
+        struct Struct {}
+        let (x, base);
+        Struct {};
+        <Struct as ToOwned>::Owned {};
+        Struct { .. };
+        Struct { ..base };
+        Struct { x };
+        Struct { x, ..base };
+        Struct { x: true };
+        Struct { x: true, .. };
+        Struct { x: true, ..base };
+        Struct { 0: true, ..base };
+    }
+    /// ExprKind::Repeat
+    fn expr_repeat() { [(); 0]; }
+    /// ExprKind::Paren
+    fn expr_paren() { let expr; (expr); }
+    /// ExprKind::Try
+    fn expr_try() { let expr; expr?; }
+    /// ExprKind::Yield
+    fn expr_yield() { yield; yield true; }
+    /// ExprKind::Yeet
+    fn expr_yeet() { do yeet; do yeet 0; }
+    /// ExprKind::Become
+    fn expr_become() { become true; }
+    /// ExprKind::IncludedBytes
+    fn expr_include_bytes() {
+        b"data for include_bytes in ../expanded-exhaustive.rs\n";
+    }
+    /// ExprKind::FormatArgs
+    fn expr_format_args() {
+        let expr;
+        format_args!("");
+        format_args!("{0}", expr);
+    }
+}
+mod items {
+    /// ItemKind::ExternCrate
+    mod item_extern_crate {
+        extern crate core;
+        extern crate self as unpretty;
+        pub extern crate core as _;
+    }
+    /// ItemKind::Use
+    mod item_use {
+        use crate::{expressions, items::item_use};
+        pub use core::*;
+    }
+    /// ItemKind::Static
+    mod item_static {
+        pub static A: () = {};
+        static mut B: () = {};
+    }
+    /// ItemKind::Const
+    mod item_const {
+        pub const A: () = {};
+        trait TraitItems {
+            const B: ();
+            const C: () = {};
+        }
+    }
+    /// ItemKind::Fn
+    mod item_fn {
+        pub const unsafe extern "C" fn f() {}
+        pub async unsafe extern fn g() {}
+        fn h<'a, T>() where T: 'a {}
+        trait TraitItems {
+            unsafe extern fn f();
+        }
+        impl TraitItems for _ {
+            default unsafe extern fn f() {}
+        }
+    }
+    /// ItemKind::Mod
+    mod item_mod { }
+    /// ItemKind::ForeignMod
+    mod item_foreign_mod {
+        extern "C++" {}
+        extern {}
+    }
+    /// ItemKind::GlobalAsm
+    mod item_global_asm {
+        global_asm! (".globl my_asm_func");
+    }
+    /// ItemKind::TyAlias
+    mod item_ty_alias {
+        pub type Type<'a> where T: 'a = T;
+    }
+    /// ItemKind::Enum
+    mod item_enum {
+        pub enum Void {}
+        enum Empty { Unit, Tuple(), Struct {}, }
+        enum Generic<'a, T> where T: 'a {
+            Tuple(T),
+            Struct {
+                t: T,
+            },
+        }
+    }
+    /// ItemKind::Struct
+    mod item_struct {
+        pub struct Unit;
+        struct Tuple();
+        struct Newtype(Unit);
+        struct Struct {}
+        struct Generic<'a, T> where T: 'a {
+            t: T,
+        }
+    }
+    /// ItemKind::Union
+    mod item_union {
+        union Generic<'a, T> where T: 'a {
+            t: T,
+        }
+    }
+    /// ItemKind::Trait
+    mod item_trait {
+        pub unsafe auto trait Send {}
+        trait Trait<'a>: Sized where Self: 'a {}
+    }
+    /// ItemKind::TraitAlias
+    mod item_trait_alias {
+        pub trait Trait<T> = Sized where for<'a> T: 'a;
+    }
+    /// ItemKind::Impl
+    mod item_impl {
+        impl () {}
+        impl<T> () {}
+        impl Default for () {}
+        impl<T> const Default for () {}
+    }
+    /// ItemKind::MacCall
+    mod item_mac_call { }
+    /// ItemKind::MacroDef
+    mod item_macro_def {
+        macro_rules! mac { () => { ... }; }
+        pub macro stringify { () => {} }
+    }
+    /// ItemKind::Delegation
+    mod item_delegation {
+        /*! FIXME: todo */
+    }
+    /// ItemKind::DelegationMac
+    mod item_delegation_mac {
+        /*! FIXME: todo */
+    }
+}
+mod patterns {
+    /// PatKind::Wild
+    fn pat_wild() { let _; }
+    /// PatKind::Ident
+    fn pat_ident() {
+        let x;
+        let ref x;
+        let mut x;
+        let ref mut x;
+        let ref mut x @ _;
+    }
+    /// PatKind::Struct
+    fn pat_struct() {
+        let T {};
+        let T::<T> {};
+        let T::<'static> {};
+        let T { x };
+        let T { x: _x };
+        let T { .. };
+        let T { x, .. };
+        let T { x: _x, .. };
+        let T { 0: _x, .. };
+        let <T as ToOwned>::Owned {};
+    }
+    /// PatKind::TupleStruct
+    fn pat_tuple_struct() {
+        struct Tuple();
+        let Tuple();
+        let Tuple::<T>();
+        let Tuple::<'static>();
+        let Tuple(x);
+        let Tuple(..);
+        let Tuple(x, ..);
+    }
+    /// PatKind::Or
+    fn pat_or() { let (true | false); let (true); let (true | false); }
+    /// PatKind::Path
+    fn pat_path() {
+        let core::marker::PhantomData;
+        let core::marker::PhantomData::<T>;
+        let core::marker::PhantomData::<'static>;
+        let <T as Trait>::CONST;
+    }
+    /// PatKind::Tuple
+    fn pat_tuple() { let (); let (true,); let (true, false); }
+    /// PatKind::Box
+    fn pat_box() { let box pat; }
+    /// PatKind::Deref
+    fn pat_deref() { let deref!(pat); }
+    /// PatKind::Ref
+    fn pat_ref() { let &pat; let &mut pat; }
+    /// PatKind::Lit
+    fn pat_lit() { let 1_000_i8; let -""; }
+    /// PatKind::Range
+    fn pat_range() { let ..1; let 0..; let 0..1; let 0..=1; let -2..=-1; }
+    /// PatKind::Slice
+    fn pat_slice() { let []; let [true]; let [true]; let [true, false]; }
+    /// PatKind::Rest
+    fn pat_rest() { let ..; }
+    /// PatKind::Never
+    fn pat_never() { let !; let Some(!); }
+    /// PatKind::Paren
+    fn pat_paren() { let (pat); }
+    /// PatKind::MacCall
+    fn pat_mac_call() { let ""; let ""; let ""; }
+}
+mod statements {
+    /// StmtKind::Let
+    fn stmt_let() {
+        let _;
+        let _ = true;
+        let _: T = true;
+        let _ = true else { return; };
+    }
+    /// StmtKind::Item
+    fn stmt_item() {
+        struct Struct {}
+        struct Unit;
+    }
+    /// StmtKind::Expr
+    fn stmt_expr() { () }
+    /// StmtKind::Semi
+    fn stmt_semi() { 1 + 1; }
+    /// StmtKind::Empty
+    fn stmt_empty() { ; }
+    /// StmtKind::MacCall
+    fn stmt_mac_call() { "..."; "..."; "..."; }
+}
+mod types {
+    /// TyKind::Slice
+    fn ty_slice() { let _: [T]; }
+    /// TyKind::Array
+    fn ty_array() { let _: [T; 0]; }
+    /// TyKind::Ptr
+    fn ty_ptr() { let _: *const T; let _: *mut T; }
+    /// TyKind::Ref
+    fn ty_ref() {
+        let _: &T;
+        let _: &mut T;
+        let _: &'static T;
+        let _: &'static mut [T];
+        let _: &T<T<T<T<T>>>>;
+        let _: &T<T<T<T<T>>>>;
+    }
+    /// TyKind::BareFn
+    fn ty_bare_fn() {
+        let _: fn();
+        let _: fn() -> ();
+        let _: fn(T);
+        let _: fn(t: T);
+        let _: fn();
+        let _: for<'a> fn();
+    }
+    /// TyKind::Never
+    fn ty_never() { let _: !; }
+    /// TyKind::Tup
+    fn ty_tup() { let _: (); let _: (T,); let _: (T, T); }
+    /// TyKind::AnonStruct
+    fn ty_anon_struct() {
+        struct Struct {
+            _: struct  {
+                t: T,
+            },
+        }
+    }
+    /// TyKind::AnonUnion
+    fn ty_anon_union() {
+        struct Struct {
+            _: union  {
+                t: T,
+            },
+        }
+    }
+    /// TyKind::Path
+    fn ty_path() {
+        let _: T;
+        let _: T<'static>;
+        let _: T<T>;
+        let _: T<T>;
+        let _: T() -> !;
+        let _: <T as ToOwned>::Owned;
+    }
+    /// TyKind::TraitObject
+    fn ty_trait_object() {
+        let _: dyn Send;
+        let _: dyn Send + 'static;
+        let _: dyn 'static + Send;
+        let _: dyn for<'a> Send;
+    }
+    /// TyKind::ImplTrait
+    const fn ty_impl_trait() {
+        let _: impl Send;
+        let _: impl Send + 'static;
+        let _: impl 'static + Send;
+        let _: impl ?Sized;
+        let _: impl ~const Clone;
+        let _: impl for<'a> Send;
+    }
+    /// TyKind::Paren
+    fn ty_paren() { let _: (T); }
+    /// TyKind::Typeof
+    fn ty_typeof() {
+        /*! unused for now */
+    }
+    /// TyKind::Infer
+    fn ty_infer() { let _: _; }
+    /// TyKind::ImplicitSelf
+    fn ty_implicit_self() {
+        /*! there is no syntax for this */
+    }
+    /// TyKind::MacCall
+    fn ty_mac_call() { let _: T; let _: T; let _: T; }
+    /// TyKind::CVarArgs
+    fn ty_c_var_args() {
+        /*! FIXME: todo */
+    }
+    /// TyKind::Pat
+    fn ty_pat() { let _: u32 is 1..; }
+}
+mod visibilities {
+    /// VisibilityKind::Public
+    mod visibility_public {
+        pub struct Pub;
+    }
+    /// VisibilityKind::Restricted
+    mod visibility_restricted {
+        pub(crate) struct PubCrate;
+        pub(self) struct PubSelf;
+        pub(super) struct PubSuper;
+        pub(in crate) struct PubInCrate;
+        pub(in self) struct PubInSelf;
+        pub(in super) struct PubInSuper;
+        pub(in crate::visibilities) struct PubInCrateVisibilities;
+        pub(in self::super) struct PubInSelfSuper;
+        pub(in super::visibility_restricted) struct PubInSuperMod;
+    }
+}
diff --git a/tests/ui/unpretty/expanded-interpolation.rs b/tests/ui/unpretty/expanded-interpolation.rs
new file mode 100644
index 0000000..8f0e21c
--- /dev/null
+++ b/tests/ui/unpretty/expanded-interpolation.rs
@@ -0,0 +1,106 @@
+//@ compile-flags: -Zunpretty=expanded
+//@ check-pass
+
+// This test covers the AST pretty-printer's insertion of parentheses in some
+// macro metavariable edge cases. Synthetic parentheses (i.e. not appearing in
+// the syntax tree) need to be printed in order for the printed code to be valid
+// Rust syntax. We also test negative cases: the pretty-printer should not be
+// synthesizing parentheses indiscriminately; only where necessary.
+
+#![feature(let_chains)]
+#![feature(if_let_guard)]
+
+macro_rules! expr {
+    ($expr:expr) => { $expr };
+}
+
+macro_rules! stmt {
+    ($stmt:stmt) => { $stmt };
+}
+
+fn if_let() {
+    macro_rules! if_let {
+        ($pat:pat, $expr:expr) => {
+            if let $pat = $expr {}
+        };
+    }
+
+    if let no_paren = true && false {}
+    if_let!(paren_around_binary, true && false);
+    if_let!(no_paren, true);
+
+    struct Struct {}
+    match () {
+        _ if let no_paren = Struct {} => {}
+    }
+}
+
+fn let_else() {
+    let no_paren = expr!(1 + 1) else { return; };
+    let paren_around_loop = expr!(loop {}) else { return; };
+}
+
+fn local() {
+    macro_rules! let_expr_minus_one {
+        ($pat:pat, $expr:expr) => {
+            let $pat = $expr - 1;
+        };
+    }
+
+    let void;
+    let_expr_minus_one!(no_paren, match void {});
+
+    macro_rules! let_expr_else_return {
+        ($pat:pat, $expr:expr) => {
+            let $pat = $expr else { return; };
+        };
+    }
+
+    let_expr_else_return!(no_paren, void());
+}
+
+fn match_arm() {
+    macro_rules! match_arm {
+        ($pat:pat, $expr:expr) => {
+            match () { $pat => $expr }
+        };
+    }
+
+    match_arm!(no_paren, 1 - 1);
+    match_arm!(paren_around_brace, { 1 } - 1);
+}
+
+/// https://github.com/rust-lang/rust/issues/98790
+fn stmt_boundary() {
+    macro_rules! expr_as_stmt {
+        ($expr:expr) => {
+            stmt!($expr)
+        };
+    }
+
+    let paren_around_match;
+    expr_as_stmt!(match paren_around_match {} | true);
+
+    macro_rules! minus_one {
+        ($expr:expr) => {
+            expr_as_stmt!($expr - 1)
+        };
+    }
+
+    let (no_paren, paren_around_loop);
+    minus_one!(no_paren);
+    minus_one!(match paren_around_match {});
+    minus_one!(match paren_around_match {}());
+    minus_one!(match paren_around_match {}[0]);
+    minus_one!(loop { break paren_around_loop; });
+}
+
+fn vis_inherited() {
+    macro_rules! vis_inherited {
+        ($vis:vis struct) => {
+            $vis struct Struct;
+        };
+    }
+
+    vis_inherited!(struct);
+}
diff --git a/tests/ui/unpretty/expanded-interpolation.stdout b/tests/ui/unpretty/expanded-interpolation.stdout
new file mode 100644
index 0000000..73322b5
--- /dev/null
+++ b/tests/ui/unpretty/expanded-interpolation.stdout
@@ -0,0 +1,92 @@
+#![feature(prelude_import)]
+#![no_std]
+//@ compile-flags: -Zunpretty=expanded
+//@ check-pass
+
+// This test covers the AST pretty-printer's insertion of parentheses in some
+// macro metavariable edge cases. Synthetic parentheses (i.e. not appearing in
+// the syntax tree) need to be printed in order for the printed code to be valid
+// Rust syntax. We also test negative cases: the pretty-printer should not be
+// synthesizing parentheses indiscriminately; only where necessary.
+
+#![feature(let_chains)]
+#![feature(if_let_guard)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+macro_rules! expr { ($expr:expr) => { $expr }; }
+
+macro_rules! stmt { ($stmt:stmt) => { $stmt }; }
+
+fn if_let() {
+    macro_rules! if_let {
+        ($pat:pat, $expr:expr) => { if let $pat = $expr {} };
+    }
+
+    if let no_paren = true && false {}
+    if let paren_around_binary = (true && false) {};
+    if let no_paren = true {};
+
+    struct Struct {}
+    match () { _ if let no_paren = Struct {} => {} }
+}
+
+fn let_else() {
+    let no_paren = 1 + 1 else { return; };
+    let paren_around_loop = (loop {}) else { return; };
+}
+
+fn local() {
+    macro_rules! let_expr_minus_one {
+        ($pat:pat, $expr:expr) => { let $pat = $expr - 1; };
+    }
+
+    let void;
+    let no_paren = match void {} - 1;
+
+    macro_rules! let_expr_else_return {
+        ($pat:pat, $expr:expr) => { let $pat = $expr else { return; }; };
+    }
+    let 
+
+            no_paren = void() else { return; };
+}
+
+fn match_arm() {
+    macro_rules! match_arm {
+        ($pat:pat, $expr:expr) => { match () { $pat => $expr } };
+    }
+    match () {
+
+
+            no_paren => 1 - 1,
+    };
+    match () { paren_around_brace => ({ 1 }) - 1, };
+}
+
+/// https://github.com/rust-lang/rust/issues/98790
+fn stmt_boundary() {
+    macro_rules! expr_as_stmt { ($expr:expr) => { stmt!($expr) }; }
+
+    let paren_around_match;
+    (match paren_around_match {}) | true;
+
+    macro_rules! minus_one { ($expr:expr) => { expr_as_stmt!($expr - 1) }; }
+
+    let (no_paren, paren_around_loop);
+    no_paren - 1;
+    (match paren_around_match {}) - 1;
+    (match paren_around_match {})() - 1;
+    (match paren_around_match {})[0] - 1;
+    (loop { break paren_around_loop; }) - 1;
+}
+
+fn vis_inherited() {
+    macro_rules! vis_inherited {
+        ($vis:vis struct) => { $vis struct Struct; };
+    }
+    struct Struct;
+
+}
diff --git a/tests/ui/unpretty/flattened-format-args.stdout b/tests/ui/unpretty/flattened-format-args.stdout
index 275fa10..2de1cdd 100644
--- a/tests/ui/unpretty/flattened-format-args.stdout
+++ b/tests/ui/unpretty/flattened-format-args.stdout
@@ -6,10 +6,10 @@
 //@ check-pass
 
 fn main() {
-        let x = 1;
-        // Should flatten to println!("a 123 b {x} xyz\n"):
-        {
-                ::std::io::_print(format_arguments::new_v1(&["a 123 b ",
-                                    " xyz\n"], &[format_argument::new_display(&x)]));
-            };
-    }
+    let x = 1;
+    // Should flatten to println!("a 123 b {x} xyz\n"):
+    {
+        ::std::io::_print(format_arguments::new_v1(&["a 123 b ", " xyz\n"],
+                &[format_argument::new_display(&x)]));
+    };
+}
diff --git a/tests/ui/unpretty/pretty-let-else.rs b/tests/ui/unpretty/let-else-hir.rs
similarity index 100%
rename from tests/ui/unpretty/pretty-let-else.rs
rename to tests/ui/unpretty/let-else-hir.rs
diff --git a/tests/ui/unpretty/pretty-let-else.stdout b/tests/ui/unpretty/let-else-hir.stdout
similarity index 61%
rename from tests/ui/unpretty/pretty-let-else.stdout
rename to tests/ui/unpretty/let-else-hir.stdout
index ed55f29..a2ffa5d 100644
--- a/tests/ui/unpretty/pretty-let-else.stdout
+++ b/tests/ui/unpretty/let-else-hir.stdout
@@ -9,10 +9,10 @@
 
 fn foo(x:
         Option<u32>) {
-        let Some(_) = x else
-            {
+    let Some(_) = x else
+        {
 
-            { ::std::rt::begin_panic("explicit panic") }
-        };
-    }
+        { ::std::rt::begin_panic("explicit panic") }
+    };
+}
 fn main() { }
diff --git a/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr b/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr
index 23bfe3c..abd59bd 100644
--- a/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr
+++ b/tests/ui/unsafe/ranged-ctor-as-fn-ptr.stderr
@@ -2,7 +2,7 @@
   --> $DIR/ranged-ctor-as-fn-ptr.rs:8:40
    |
 LL |     let x: fn(u8) -> NonZeroAndOneU8 = NonZeroAndOneU8;
-   |            -------------------------   ^^^^^^^^^^^^^^^ expected normal fn, found unsafe fn
+   |            -------------------------   ^^^^^^^^^^^^^^^ expected safe fn, found unsafe fn
    |            |
    |            expected due to this
    |
diff --git a/tests/ui/unsafe/unsafe-subtyping.stderr b/tests/ui/unsafe/unsafe-subtyping.stderr
index 1cc949c..ddeeaa5 100644
--- a/tests/ui/unsafe/unsafe-subtyping.stderr
+++ b/tests/ui/unsafe/unsafe-subtyping.stderr
@@ -4,7 +4,7 @@
 LL | fn foo(x: Option<fn(i32)>) -> Option<unsafe fn(i32)> {
    |                               ---------------------- expected `Option<unsafe fn(i32)>` because of return type
 LL |     x
-   |     ^ expected unsafe fn, found normal fn
+   |     ^ expected unsafe fn, found safe fn
    |
    = note: expected enum `Option<unsafe fn(_)>`
               found enum `Option<fn(_)>`
diff --git a/tests/ui/unsafe/unsafe-trait-impl.stderr b/tests/ui/unsafe/unsafe-trait-impl.stderr
index 5888b67..b9f2e1c 100644
--- a/tests/ui/unsafe/unsafe-trait-impl.stderr
+++ b/tests/ui/unsafe/unsafe-trait-impl.stderr
@@ -2,7 +2,7 @@
   --> $DIR/unsafe-trait-impl.rs:8:5
    |
 LL |     fn len(&self) -> u32 { *self }
-   |     ^^^^^^^^^^^^^^^^^^^^ expected unsafe fn, found normal fn
+   |     ^^^^^^^^^^^^^^^^^^^^ expected unsafe fn, found safe fn
    |
 note: type in trait
   --> $DIR/unsafe-trait-impl.rs:4:5
diff --git a/tests/ui/use/use-nested-groups-unused-imports.rs b/tests/ui/use/use-nested-groups-unused-imports.rs
index ca6b8ba..0c8ae55 100644
--- a/tests/ui/use/use-nested-groups-unused-imports.rs
+++ b/tests/ui/use/use-nested-groups-unused-imports.rs
@@ -13,7 +13,7 @@
 }
 
 use foo::{Foo, bar::{baz::{}, foobar::*}, *};
-    //~^ ERROR unused imports: `*`, `Foo`, `baz::{}`, `foobar::*`
+    //~^ ERROR unused imports: `*`, `Foo`, `baz::{}`, and `foobar::*`
 use foo::bar::baz::{*, *};
     //~^ ERROR unused import: `*`
 use foo::{};
diff --git a/tests/ui/use/use-nested-groups-unused-imports.stderr b/tests/ui/use/use-nested-groups-unused-imports.stderr
index 6610f8e..dd39a85 100644
--- a/tests/ui/use/use-nested-groups-unused-imports.stderr
+++ b/tests/ui/use/use-nested-groups-unused-imports.stderr
@@ -1,4 +1,4 @@
-error: unused imports: `*`, `Foo`, `baz::{}`, `foobar::*`
+error: unused imports: `*`, `Foo`, `baz::{}`, and `foobar::*`
   --> $DIR/use-nested-groups-unused-imports.rs:15:11
    |
 LL | use foo::{Foo, bar::{baz::{}, foobar::*}, *};
diff --git a/tests/ui/version/version-info-flags.rs b/tests/ui/version/version-info-flags.rs
index 6121134..96be9c5 100644
--- a/tests/ui/version/version-info-flags.rs
+++ b/tests/ui/version/version-info-flags.rs
@@ -4,6 +4,6 @@
 //@ check-pass
 //@[version] compile-flags: -V
 //@[verbose-version] compile-flags: -vV
-//@[long-verbose-verison] compile-flags: --version --verbose
+//@[long-verbose-version] compile-flags: --version --verbose
 
 fn main() {}
diff --git a/tests/ui/wait-forked-but-failed-child.rs b/tests/ui/wait-forked-but-failed-child.rs
index 3d052cc..dd6a7fa 100644
--- a/tests/ui/wait-forked-but-failed-child.rs
+++ b/tests/ui/wait-forked-but-failed-child.rs
@@ -7,8 +7,6 @@
 
 #![feature(rustc_private)]
 
-extern crate libc;
-
 use std::process::Command;
 
 // The output from "ps -A -o pid,ppid,args" should look like this:
@@ -28,6 +26,7 @@
 
 #[cfg(unix)]
 fn find_zombies() {
+    extern crate libc;
     let my_pid = unsafe { libc::getpid() };
 
     // https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html
diff --git a/tests/ui/wf/wf-normalization-sized.next.stderr b/tests/ui/wf/wf-normalization-sized.next.stderr
index 599b1f3..1e898fb 100644
--- a/tests/ui/wf/wf-normalization-sized.next.stderr
+++ b/tests/ui/wf/wf-normalization-sized.next.stderr
@@ -1,30 +1,37 @@
-error: the type `<[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize` is not well-formed
-  --> $DIR/wf-normalization-sized.rs:19:10
+error[E0277]: the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
+  --> $DIR/wf-normalization-sized.rs:19:11
    |
 LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `[[[[[u8]]]]]`
 
-error: the type `<[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize` is not well-formed
-  --> $DIR/wf-normalization-sized.rs:19:10
+error[E0277]: the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
+  --> $DIR/wf-normalization-sized.rs:19:11
    |
 LL | const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^^^^^^^ doesn't have a size known at compile-time
    |
+   = help: the trait `Sized` is not implemented for `[[[[[u8]]]]]`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
-error: the type `<Vec<str> as WellUnformed>::RequestNormalize` is not well-formed
-  --> $DIR/wf-normalization-sized.rs:22:10
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/wf-normalization-sized.rs:22:11
    |
 LL | const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: the trait `Sized` is not implemented for `str`
 
-error: the type `<Vec<str> as WellUnformed>::RequestNormalize` is not well-formed
-  --> $DIR/wf-normalization-sized.rs:22:10
+error[E0277]: the size for values of type `str` cannot be known at compilation time
+  --> $DIR/wf-normalization-sized.rs:22:11
    |
 LL | const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
-   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |           ^^^^^^^^ doesn't have a size known at compile-time
    |
+   = help: the trait `Sized` is not implemented for `str`
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: aborting due to 4 previous errors
 
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/wf/wf-normalization-sized.rs b/tests/ui/wf/wf-normalization-sized.rs
index e6e24ff..80b2c88 100644
--- a/tests/ui/wf/wf-normalization-sized.rs
+++ b/tests/ui/wf/wf-normalization-sized.rs
@@ -17,10 +17,10 @@
 }
 
 const _: <[[[[[[u8]]]]]] as WellUnformed>::RequestNormalize = ();
-//[next]~^ the type
-//[next]~| the type
+//[next]~^ the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
+//[next]~| the size for values of type `[[[[[u8]]]]]` cannot be known at compilation time
 const _: <Vec<str> as WellUnformed>::RequestNormalize = ();
-//[next]~^ the type
-//[next]~| the type
+//[next]~^ the size for values of type `str` cannot be known at compilation time
+//[next]~| the size for values of type `str` cannot be known at compilation time
 
 fn main() {}
diff --git a/tests/ui/write-fmt-errors.rs b/tests/ui/write-fmt-errors.rs
index f194e25..1dafb9a 100644
--- a/tests/ui/write-fmt-errors.rs
+++ b/tests/ui/write-fmt-errors.rs
@@ -1,9 +1,11 @@
 //@ run-pass
+//@ needs-unwind
 
 #![feature(io_error_uncategorized)]
 
 use std::fmt;
 use std::io::{self, Error, Write, sink};
+use std::panic::catch_unwind;
 
 struct ErrorDisplay;
 
@@ -15,7 +17,6 @@
 
 struct ErrorWriter;
 
-const FORMAT_ERROR: io::ErrorKind = io::ErrorKind::Uncategorized;
 const WRITER_ERROR: io::ErrorKind = io::ErrorKind::NotConnected;
 
 impl Write for ErrorWriter {
@@ -27,22 +28,28 @@
 }
 
 fn main() {
-    // Test that the error from the formatter is propagated.
-    let res = write!(sink(), "{} {} {}", 1, ErrorDisplay, "bar");
-    assert!(res.is_err(), "formatter error did not propagate");
-    assert_eq!(res.unwrap_err().kind(), FORMAT_ERROR);
-
     // Test that an underlying error is propagated
     let res = write!(ErrorWriter, "abc");
     assert!(res.is_err(), "writer error did not propagate");
 
-    // Writer error
+    // Test that the error from the formatter is detected.
+    let res = catch_unwind(|| write!(sink(), "{} {} {}", 1, ErrorDisplay, "bar"));
+    let err = res.expect_err("formatter error did not lead to panic").downcast::<&str>().unwrap();
+    assert!(
+        err.contains("formatting trait implementation returned an error"),
+        "unexpected panic: {}", err
+    );
+
+    // Writer error when there's some string before the first `{}`
     let res = write!(ErrorWriter, "abc {}", ErrorDisplay);
     assert!(res.is_err(), "writer error did not propagate");
     assert_eq!(res.unwrap_err().kind(), WRITER_ERROR);
 
-    // Formatter error
-    let res = write!(ErrorWriter, "{} abc", ErrorDisplay);
-    assert!(res.is_err(), "formatter error did not propagate");
-    assert_eq!(res.unwrap_err().kind(), FORMAT_ERROR);
+    // Formatter error when the `{}` comes first
+    let res = catch_unwind(|| write!(ErrorWriter, "{} abc", ErrorDisplay));
+    let err = res.expect_err("formatter error did not lead to panic").downcast::<&str>().unwrap();
+    assert!(
+        err.contains("formatting trait implementation returned an error"),
+        "unexpected panic: {}", err
+    );
 }
diff --git a/triagebot.toml b/triagebot.toml
index dd6a03f..2e45b25 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -9,11 +9,14 @@
     "E-*",
     "F-*",
     "I-*",
+    "L-*",
     "NLL-*",
     "O-*",
+    "PG-*",
     "S-*",
     "T-*",
     "WG-*",
+    "-Z*",
     "beta-nominated",
     "const-hack",
     "llvm-*",
@@ -310,7 +313,7 @@
     "configure",
     "Cargo.toml",
     "config.example.toml",
-    "src/stage0.json",
+    "src/stage0",
     "src/tools/compiletest",
     "src/tools/tidy",
     "src/tools/rustdoc-gui-test",
@@ -370,7 +373,7 @@
 [autolabel."T-release"]
 trigger_files = [
     "RELEASES.md",
-    "src/stage0.json",
+    "src/stage0",
     "src/version"
 ]
 
@@ -419,7 +422,7 @@
 - Priority?
 - Regression?
 - Notify people/groups?
-- Needs `I-nominated`?
+- Needs `I-{team}-nominated`?
 """
 message_on_remove = "Issue #{number}'s prioritization request has been removed."
 message_on_close = "Issue #{number} has been closed while requested for prioritization."
@@ -864,6 +867,7 @@
     "@fmease",
     "@fee1-dead",
     "@jieyouxu",
+    "@BoxyUwU",
 ]
 compiler = [
     "compiler-team",
@@ -933,11 +937,13 @@
 mir = [
     "@davidtwco",
     "@oli-obk",
-    "@matthewjasper"
+    "@matthewjasper",
+    "@saethlin",
 ]
 mir-opt = [
     "@oli-obk",
     "@wesleywiser",
+    "@saethlin",
 ]
 types = [
     "@compiler-errors",
@@ -1003,6 +1009,7 @@
 "/compiler/rustc_lexer" =                                ["compiler", "lexer"]
 "/compiler/rustc_llvm" =                                 ["@cuviper"]
 "/compiler/rustc_codegen_llvm/src/debuginfo" =           ["compiler", "debuginfo"]
+"/compiler/rustc_codegen_ssa" =                          ["compiler", "@saethlin"]
 "/compiler/rustc_middle/src/mir" =                       ["compiler", "mir"]
 "/compiler/rustc_middle/src/traits" =                    ["compiler", "types"]
 "/compiler/rustc_middle/src/ty" =                        ["compiler", "types"]
@@ -1046,7 +1053,7 @@
 "/src/librustdoc" =                                      ["rustdoc"]
 "/src/llvm-project" =                                    ["@cuviper"]
 "/src/rustdoc-json-types" =                              ["rustdoc"]
-"/src/stage0.json" =                                     ["bootstrap"]
+"/src/stage0" =                                          ["bootstrap"]
 "/tests/run-make" =                                      ["@jieyouxu"]
 "/tests/ui" =                                            ["compiler"]
 "/src/tools/cargo" =                                     ["@ehuss"]